You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by at...@apache.org on 2014/08/04 12:35:43 UTC
git commit: AMBARI-6726 Config History: E2E Integration of Config
Version History Table. (atkach)
Repository: ambari
Updated Branches:
refs/heads/trunk 9d665447e -> 80b2a1f2e
AMBARI-6726 Config History: E2E Integration of Config Version History Table. (atkach)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/80b2a1f2
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/80b2a1f2
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/80b2a1f2
Branch: refs/heads/trunk
Commit: 80b2a1f2e27294f4228bf83ded3d755d120ad0d2
Parents: 9d66544
Author: atkach <at...@hortonworks.com>
Authored: Mon Aug 4 13:33:05 2014 +0300
Committer: atkach <at...@hortonworks.com>
Committed: Mon Aug 4 13:33:05 2014 +0300
----------------------------------------------------------------------
.../main/dashboard/config_history_controller.js | 139 +++++++++++++++--
ambari-web/app/controllers/main/host.js | 2 +
.../mappers/service_config_version_mapper.js | 23 ++-
ambari-web/app/messages.js | 2 +-
ambari-web/app/mixins.js | 1 +
.../app/mixins/common/tableServerProvider.js | 25 ----
.../app/mixins/common/table_server_mixin.js | 148 +++++++++++++++++++
ambari-web/app/models/service_config_version.js | 20 ++-
.../templates/main/dashboard/config_history.hbs | 38 +++--
.../app/views/common/custom_date_popup.js | 127 ++++++++++++++++
ambari-web/app/views/common/filter_view.js | 15 +-
ambari-web/app/views/common/table_view.js | 31 ++--
.../views/main/dashboard/config_history_view.js | 104 ++++++++++---
ambari-web/app/views/main/host.js | 5 -
14 files changed, 578 insertions(+), 102 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/80b2a1f2/ambari-web/app/controllers/main/dashboard/config_history_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/dashboard/config_history_controller.js b/ambari-web/app/controllers/main/dashboard/config_history_controller.js
index 493f499..8989b56 100644
--- a/ambari-web/app/controllers/main/dashboard/config_history_controller.js
+++ b/ambari-web/app/controllers/main/dashboard/config_history_controller.js
@@ -16,28 +16,124 @@
* limitations under the License.
*/
-App.MainConfigHistoryController = Em.ArrayController.extend({
+var customDatePopup = require('/views/common/custom_date_popup');
+
+App.MainConfigHistoryController = Em.ArrayController.extend(App.TableServerMixin, {
name: 'mainConfigHistoryController',
dataSource: App.ServiceConfigVersion.find(),
content: function () {
- return this.get('dataSource').toArray();
- }.property('dataSource.@each.isLoaded'),
- isLoaded: false,
+ return this.get('dataSource').filterProperty('isRequested');
+ }.property('dataSource.@each.isRequested'),
isPolling: false,
+ filteredCount: 0,
+ mockUrl: '/data/configurations/service_versions.json',
+ realUrl: function () {
+ return App.apiPrefix + '/clusters/' + App.get('clusterName') + '/configurations/serviceconfigversions?<parameters>fields=serviceconfigversion,user,appliedtime,createtime,service_name&minimal_response=true';
+ }.property('App.clusterName'),
/**
- * initial data load
+ * associations between host property and column index
+ * @type {Array}
*/
- load: function () {
- var self = this;
+ colPropAssoc: function () {
+ var associations = [];
+ associations[1] = 'serviceVersion';
+ associations[2] = 'appliedTime';
+ associations[3] = 'author';
+ associations[4] = 'notes';
+ return associations;
+ }.property(),
- this.set('isLoaded', false);
- this.loadHistoryToModel().done(function () {
- self.set('isLoaded', true);
- self.doPolling();
- });
- },
+ filterProps: [
+ {
+ name: 'serviceVersion',
+ key: 'service_name',
+ type: 'EQUAL'
+ },
+ {
+ name: 'appliedTime',
+ key: 'appliedtime',
+ type: 'MORE'
+ },
+ {
+ name: 'author',
+ key: 'user',
+ type: 'MATCH'
+ }
+ //TODO uncomment when API contains "notes" property
+ /*,
+ {
+ name: 'notes',
+ key: '',
+ type: 'MATCH'
+ }*/
+ ],
+
+ sortProps: [
+ {
+ name: 'serviceVersion',
+ key: 'service_name'
+ },
+ {
+ name: 'appliedTime',
+ key: 'appliedtime'
+ },
+ {
+ name: 'author',
+ key: 'user'
+ }/*,
+ {
+ name: 'notes',
+ key: ''
+ }*/
+ ],
+
+ modifiedFilter: Em.Object.create({
+ optionValue: 'Any',
+ filterModified: function () {
+ var time = "";
+ var curTime = new Date().getTime();
+
+ switch (this.get('optionValue')) {
+ 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':
+ customDatePopup.showCustomDatePopup(this, this.get('actualValues'));
+ break;
+ case 'Any':
+ time = "";
+ break;
+ }
+ if (this.get('modified') !== "Custom") {
+ this.set("actualValues.startTime", time);
+ this.set("actualValues.endTime", '');
+ }
+ }.observes('optionValue'),
+ cancel: function () {
+ this.set('optionValue', 'Any');
+ },
+ actualValues: Em.Object.create({
+ startTime: "",
+ endTime: ""
+ })
+ }),
/**
* get data from server and push it to model
@@ -45,10 +141,9 @@ App.MainConfigHistoryController = Em.ArrayController.extend({
*/
loadHistoryToModel: function () {
var dfd = $.Deferred();
+ var queryParams = this.getQueryParameters();
- var url = '/data/configurations/service_versions.json';
-
- App.HttpClient.get(url, App.serviceConfigVersionsMapper, {
+ App.HttpClient.get(this.getUrl(queryParams), App.serviceConfigVersionsMapper, {
complete: function () {
dfd.resolve();
}
@@ -56,6 +151,18 @@ App.MainConfigHistoryController = Em.ArrayController.extend({
return dfd.promise();
},
+ getUrl: function (queryParams) {
+ var params = '';
+ if (App.get('testMode')) {
+ return this.get('mockUrl');
+ } else {
+ if (queryParams) {
+ params = App.router.get('updateController').computeParameters(queryParams);
+ }
+ return this.get('realUrl').replace('<parameters>', params);
+ }
+ },
+
/**
* request latest data from server and update content
*/
http://git-wip-us.apache.org/repos/asf/ambari/blob/80b2a1f2/ambari-web/app/controllers/main/host.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/host.js b/ambari-web/app/controllers/main/host.js
index 6b9210a..227a091 100644
--- a/ambari-web/app/controllers/main/host.js
+++ b/ambari-web/app/controllers/main/host.js
@@ -79,6 +79,8 @@ App.MainHostController = Em.ArrayController.extend({
* filterProperties support follow types of filter:
* MATCH - match of RegExp
* EQUAL - equality "="
+ * LESS - "<"
+ * MORE - ">"
* MULTIPLE - multiple values to compare
* CUSTOM - substitute values with keys "{#}" in alias
*/
http://git-wip-us.apache.org/repos/asf/ambari/blob/80b2a1f2/ambari-web/app/mappers/service_config_version_mapper.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mappers/service_config_version_mapper.js b/ambari-web/app/mappers/service_config_version_mapper.js
index 93fc2b8..1dbf99c 100644
--- a/ambari-web/app/mappers/service_config_version_mapper.js
+++ b/ambari-web/app/mappers/service_config_version_mapper.js
@@ -21,23 +21,38 @@ var App = require('app');
App.serviceConfigVersionsMapper = App.QuickDataMapper.create({
model: App.ServiceConfigVersion,
config: {
- service_name: 'servicename',
+ service_name: 'service_name',
+ service_id: 'service_name',
version: "serviceconfigversion",
create_time: 'createtime',
applied_time: 'appliedtime',
- author: 'author',
- notes: 'notes'
+ author: 'user',
+ notes: 'notes',
+ index: 'index'
},
map: function (json) {
var result = [];
+ var itemIds = {};
if (json && json.items) {
- json.items.forEach(function (item) {
+ json.items.forEach(function (item, index) {
var parsedItem = this.parseIt(item, this.get('config'));
parsedItem.id = parsedItem.service_name + '_' + parsedItem.version;
+ parsedItem.is_requested = true;
+ itemIds[parsedItem.id] = true;
+ parsedItem.index = index;
result.push(parsedItem);
}, this);
+ this.get('model').find().forEach(function (item) {
+ if (!itemIds[item.get('id')]) {
+ item.set('isRequested', false);
+ }
+ });
+ var itemTotal = parseInt(json.itemTotal);
+ if (!isNaN(itemTotal)) {
+ App.router.set('mainConfigHistoryController.filteredCount', itemTotal);
+ }
App.store.loadMany(this.get('model'), result);
}
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/80b2a1f2/ambari-web/app/messages.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js
index 42724d3..68e9d51 100644
--- a/ambari-web/app/messages.js
+++ b/ambari-web/app/messages.js
@@ -215,6 +215,7 @@ Em.I18n.translations = {
'common.notes': 'Notes',
'common.view': 'View',
'common.compare': 'Compare',
+ 'common.latest': 'Latest',
'passiveState.turnOn':'Turn On Maintenance Mode',
'passiveState.turnOff':'Turn Off Maintenance Mode',
@@ -1961,7 +1962,6 @@ Em.I18n.translations = {
'dashboard.configHistory.table.modified.title' : 'Modified',
'dashboard.configHistory.table.empty' : 'No history to display',
'dashboard.configHistory.table.filteredHostsInfo': '{0} of {1} versions showing',
- 'dashboard.configHistory.table.current': '(Current)',
'dashboard.configHistory.info-bar.authoredOn': 'authored on',
'dashboard.configHistory.info-bar.changesToHandle': 'Changes to handle',
'dashboard.configHistory.info-bar.showMore': 'Show more',
http://git-wip-us.apache.org/repos/asf/ambari/blob/80b2a1f2/ambari-web/app/mixins.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins.js b/ambari-web/app/mixins.js
index ba5d51f..98cc3d8 100644
--- a/ambari-web/app/mixins.js
+++ b/ambari-web/app/mixins.js
@@ -23,5 +23,6 @@ require('mixins/common/localStorage');
require('mixins/common/userPref');
require('mixins/models/service_mixin');
require('mixins/common/tableServerProvider');
+require('mixins/common/table_server_mixin');
require('mixins/main/host/details/host_components/decommissionable');
require('mixins/wizard/selectHost');
http://git-wip-us.apache.org/repos/asf/ambari/blob/80b2a1f2/ambari-web/app/mixins/common/tableServerProvider.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins/common/tableServerProvider.js b/ambari-web/app/mixins/common/tableServerProvider.js
index b1942ce..4ba45d1 100644
--- a/ambari-web/app/mixins/common/tableServerProvider.js
+++ b/ambari-web/app/mixins/common/tableServerProvider.js
@@ -96,30 +96,5 @@ App.TableServerProvider = Em.Mixin.create({
this.refresh();
}
}
- },
-
- /**
- * save filter conditions to local storage
- * @param iColumn {Number}
- * @param value {String|Array}
- * @param type {String}
- * @param skipFilter {Boolean}
- */
- saveFilterConditions: function (iColumn, value, type, skipFilter) {
- var filterCondition = this.get('filterConditions').findProperty('iColumn', iColumn);
-
- if (filterCondition) {
- filterCondition.value = value;
- filterCondition.skipFilter = skipFilter;
- } else {
- filterCondition = {
- skipFilter: skipFilter,
- iColumn: iColumn,
- value: value,
- type: type
- };
- this.get('filterConditions').push(filterCondition);
- }
- App.db.setFilterConditions(this.get('controller.name'), this.get('filterConditions'));
}
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/80b2a1f2/ambari-web/app/mixins/common/table_server_mixin.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins/common/table_server_mixin.js b/ambari-web/app/mixins/common/table_server_mixin.js
new file mode 100644
index 0000000..d449125
--- /dev/null
+++ b/ambari-web/app/mixins/common/table_server_mixin.js
@@ -0,0 +1,148 @@
+/**
+ * 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.
+ */
+
+var App = require('app');
+var validator = require('utils/validator');
+
+//TODO integrate mixin into mainHostController to avoid code duplication
+App.TableServerMixin = Em.Mixin.create({
+ queryParams: [],
+ resetStartIndex: false,
+ /**
+ * filterProps support follow types of filter:
+ * MATCH - match of RegExp
+ * EQUAL - equality "="
+ * LESS - "<"
+ * MORE - ">"
+ * MULTIPLE - multiple values to compare
+ * CUSTOM - substitute values with keys "{#}" in alias
+ */
+ filterProps: [],
+ /**
+ * include "from" nad "page_size"
+ */
+ paginationProps: [
+ {
+ name: 'displayLength',
+ key: 'page_size',
+ value: '25',
+ type: 'EQUAL'
+ },
+ {
+ name: 'startIndex',
+ key: 'from',
+ value: 0,
+ type: 'EQUAL'
+ }
+ ],
+ sortProps: [],
+
+ /**
+ * update values of pagination properties from local db and return them
+ * @return {array}
+ */
+ getPaginationProps: function () {
+ var displayLength = App.db.getDisplayLength(this.get('name'));
+ if (displayLength) {
+ this.get('paginationProps').findProperty('name', 'displayLength').value = displayLength;
+ }
+
+ var startIndex = App.db.getStartIndex(this.get('name'));
+ if (!Em.isNone(startIndex)) {
+ startIndex = (startIndex > 0) ? startIndex - 1 : startIndex;
+ if (this.get('resetStartIndex')) {
+ startIndex = 0;
+ }
+ this.get('paginationProps').findProperty('name', 'startIndex').value = startIndex;
+ }
+ return this.get('paginationProps');
+ },
+
+ /**
+ * get sort properties from local db
+ * @return {Array}
+ */
+ getSortProps: function () {
+ var savedSortConditions = App.db.getSortingStatuses(this.get('name')) || [],
+ sortProperties = this.get('sortProps'),
+ sortParams = [];
+
+ savedSortConditions.forEach(function (sort) {
+ var property = sortProperties.findProperty('name', sort.name);
+
+ if (property && (sort.status === 'sorting_asc' || sort.status === 'sorting_desc')) {
+ property.value = sort.status.replace('sorting_', '');
+ property.type = 'SORT';
+ sortParams.push(property);
+ }
+ });
+ return sortParams;
+ },
+ /**
+ * get filter properties from local db
+ * @return {Array}
+ */
+ getFilterProps: function () {
+ var savedFilterConditions = App.db.getFilterConditions(this.get('name')) || [],
+ filterProperties = this.get('filterProps'),
+ filterParams = [],
+ colPropAssoc = this.get('colPropAssoc');
+
+ savedFilterConditions.forEach(function (filter) {
+ var property = filterProperties.findProperty('name', colPropAssoc[filter.iColumn]);
+
+ if (property && filter.value.length > 0 && !filter.skipFilter) {
+ property.isFilter = true;
+
+ if (filter.type === 'range') {
+ //range value should contain array of two element with start and end values accordingly
+ filter.value.forEach(function (val, index) {
+ if (val) {
+ property.type = (index === 0) ? "MORE" : "LESS";
+ property.value = val;
+ filterParams.push(property);
+ }
+ });
+ } else if (filter.type === 'string') {
+ property.value = this.getRegExp(filter.value);
+ } else {
+ property.value = filter.value;
+ filterParams.push(property);
+ }
+ }
+ }, this);
+ return filterParams;
+ },
+
+ getQueryParameters: function () {
+ var queryParams = [];
+
+ queryParams.pushObjects(this.getPaginationProps());
+ queryParams.pushObjects(this.getSortProps());
+ queryParams.pushObjects(this.getFilterProps());
+ this.set('queryParams', queryParams);
+ return queryParams;
+ },
+
+ getRegExp: function (value) {
+ value = validator.isValidMatchesRegexp(value) ? value.replace(/(\.+\*?|(\.\*)+)$/, '') + '.*' : '^$';
+ value = /^\.\*/.test(value) || value == '^$' ? value : '.*' + value;
+ return value;
+ }
+
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/80b2a1f2/ambari-web/app/models/service_config_version.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/service_config_version.js b/ambari-web/app/models/service_config_version.js
index 10552fd..2c52d22 100644
--- a/ambari-web/app/models/service_config_version.js
+++ b/ambari-web/app/models/service_config_version.js
@@ -28,13 +28,23 @@ App.ServiceConfigVersion = DS.Model.extend({
appliedTime: DS.attr('number'),
author: DS.attr('string'),
notes: DS.attr('string'),
- serviceVersion: function(){
- return this.get('serviceName') + ': '+ this.get('version');
+ service: DS.belongsTo('App.Service'),
+ index: DS.attr('number'),
+ serviceVersion: function () {
+ return this.get('serviceName') + ': ' + this.get('version');
}.property('serviceName', 'version'),
- modifiedDate: function() {
- return dateUtil.dateFormat(this.get('createTime'));
+ modifiedDate: function () {
+ return dateUtil.dateFormat(this.get('appliedTime'));
}.property('createTime'),
- isCurrent: true
+ //TODO set isCurrent value from API response
+ isCurrent: false,
+ /**
+ * determine whether ServiceConfigVersion is requested from server
+ */
+ isRequested: DS.attr('boolean'),
+ isRestartRequired: function () {
+ return this.get('service.isRestartRequired');
+ }.property('service.isRestartRequired')
});
App.ServiceConfigVersion.FIXTURES = [];
http://git-wip-us.apache.org/repos/asf/ambari/blob/80b2a1f2/ambari-web/app/templates/main/dashboard/config_history.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/dashboard/config_history.hbs b/ambari-web/app/templates/main/dashboard/config_history.hbs
index 88ee4b9..6306078 100644
--- a/ambari-web/app/templates/main/dashboard/config_history.hbs
+++ b/ambari-web/app/templates/main/dashboard/config_history.hbs
@@ -27,30 +27,36 @@
{{/view}}
<tr class="filter-row">
- <th class="first">{{view view.versionFilterView}}</th>
+ <th class="first">{{view view.serviceFilterView}}</th>
<th>{{view view.modifiedFilterView}}</th>
<th>{{view view.authorFilterView}}</th>
<th>{{view view.notesFilterView}}</th>
</tr>
</thead>
- <tbody>
- {{#if view.pageContent}}
- {{#each item in view.pageContent}}
+ <tbody class="services-menu">
+ {{#if view.filteringComplete}}
+ {{#if view.pageContent}}
+ {{#each item in view.pageContent}}
+ <tr>
+ <td class="first"><a {{action goToServiceConfigs item.serviceName}}>
+ {{item.serviceVersion}}
+ {{#if item.isCurrent}} ({{t common.latest}}){{/if}}
+ <i {{bindAttr class=":icon-refresh :restart-required-service item.isRestartRequired::hidden"}}></i>
+ </a></td>
+ <td>{{item.modifiedDate}}</td>
+ <td>{{item.author}}</td>
+ <td>{{item.notes}}</td>
+ </tr>
+ {{/each}}
+ {{else}}
<tr>
- <td class="first"><a {{action goToServiceConfigs item.serviceName}}>
- {{item.serviceVersion}}{{#if item.isCurrent}} {{t dashboard.configHistory.table.current}}{{/if}}
- </a></td>
- <td>{{item.modifiedDate}}</td>
- <td>{{item.author}}</td>
- <td>{{item.notes}}</td>
+ <td class="first" colspan="4">
+ {{t dashboard.configHistory.table.empty}}
+ </td>
</tr>
- {{/each}}
+ {{/if}}
{{else}}
- <tr>
- <td class="first" colspan="4">
- {{t dashboard.configHistory.table.empty}}
- </td>
- </tr>
+ <tr><td colspan="4"><div class="spinner"></div></td></tr>
{{/if}}
</tbody>
</table>
http://git-wip-us.apache.org/repos/asf/ambari/blob/80b2a1f2/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
new file mode 100644
index 0000000..d018e07
--- /dev/null
+++ b/ambari-web/app/views/common/custom_date_popup.js
@@ -0,0 +1,127 @@
+/**
+ * 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.
+ */
+
+var App = require('app');
+
+module.exports = Em.Object.create({
+
+ // Fields values from Select Custom Dates form
+ customDateFormFields: Ember.Object.create({
+ startDate: null,
+ hoursForStart: null,
+ minutesForStart: null,
+ middayPeriodForStart: null,
+ endDate: null,
+ hoursForEnd: null,
+ minutesForEnd: null,
+ middayPeriodForEnd: null
+ }),
+
+ errors: Ember.Object.create({
+ isStartDateError: false,
+ isEndDateError: false
+ }),
+
+ errorMessages: Ember.Object.create({
+ startDate: '',
+ endDate: ''
+ }),
+
+ showCustomDatePopup: function (context, valueObject) {
+ var self = this;
+
+ 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 false;
+ }
+
+ var windowStart = self.createCustomStartDate();
+ var windowEnd = self.createCustomEndDate();
+
+ valueObject.set("endTime", windowEnd.getTime());
+ valueObject.set("startTime", windowStart.getTime());
+ this.hide();
+ },
+ onSecondary: function () {
+ context.cancel();
+ this.hide();
+ },
+ bodyClass: App.JobsCustomDatesSelectView.extend({
+ controller: self
+ })
+ });
+ },
+
+ 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 null;
+ },
+
+ createCustomEndDate : function () {
+ var endDate = this.get('customDateFormFields.endDate');
+ var hoursForEnd = this.get('customDateFormFields.hoursForEnd');
+ var minutesForEnd = this.get('customDateFormFields.minutesForEnd');
+ var middayPeriodForEnd = this.get('customDateFormFields.middayPeriodForEnd');
+ if (endDate && hoursForEnd && minutesForEnd && middayPeriodForEnd) {
+ return new Date(endDate + ' ' + hoursForEnd + ':' + minutesForEnd + ' ' + middayPeriodForEnd);
+ }
+ return null;
+ },
+
+ clearErrors: function () {
+ var errorMessages = this.get('errorMessages');
+ Em.keys(errorMessages).forEach(function (key) {
+ errorMessages.set(key, '');
+ }, this);
+ var errors = this.get('errors');
+ Em.keys(errors).forEach(function (key) {
+ errors.set(key, false);
+ }, this);
+ },
+
+ // Validation for every field in customDateFormFields
+ validate: function () {
+ var formFields = this.get('customDateFormFields');
+ var errors = this.get('errors');
+ var errorMessages = this.get('errorMessages');
+ this.clearErrors();
+ // Check if feild is empty
+ Em.keys(errorMessages).forEach(function (key) {
+ if (!formFields.get(key)) {
+ errors.set('is' + key.capitalize() + 'Error', true);
+ errorMessages.set(key, Em.I18n.t('jobs.customDateFilter.error.required'));
+ }
+ }, this);
+ // Check that endDate is after startDate
+ var startDate = this.createCustomStartDate();
+ var endDate = this.createCustomEndDate();
+ if (startDate && endDate && (startDate > endDate)) {
+ errors.set('isEndDateError', true);
+ errorMessages.set('endDate', Em.I18n.t('jobs.customDateFilter.error.date.order'));
+ }
+ }
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/80b2a1f2/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 851557d..93c2d90 100644
--- a/ambari-web/app/views/common/filter_view.js
+++ b/ambari-web/app/views/common/filter_view.js
@@ -72,11 +72,18 @@ var wrapperView = Ember.View.extend({
emptyValue: '',
/**
+ * reset value to empty string if emptyValue selected
+ */
+ actualValue: function () {
+ return this.get('value') === this.get('emptyValue') ? "" : this.get('value');
+ }.property('value'),
+
+ /**
* Whether our <code>value</code> is empty or not
* @return {Boolean}
*/
isEmpty: function(){
- if(this.get('value') === null){
+ if (Em.isNone(this.get('value'))) {
return true;
}
return this.get('value').toString() === this.get('emptyValue').toString();
@@ -486,6 +493,12 @@ module.exports = {
return true;
};
break;
+ case 'range':
+ return function (origin, compareValue){
+ //TODO add filter by range value
+ return true;
+ };
+ break;
case 'string':
default:
return function(origin, compareValue){
http://git-wip-us.apache.org/repos/asf/ambari/blob/80b2a1f2/ambari-web/app/views/common/table_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/table_view.js b/ambari-web/app/views/common/table_view.js
index 2121d8a..a234675 100644
--- a/ambari-web/app/views/common/table_view.js
+++ b/ambari-web/app/views/common/table_view.js
@@ -96,7 +96,11 @@ App.TableView = Em.View.extend(App.UserPref, {
filterConditions.forEach(function (condition, index, filteredConditions) {
var view = !Em.isNone(condition.iColumn) && childViews.findProperty('column', condition.iColumn);
if (view) {
- view.set('value', condition.value);
+ if (view.get('emptyValue')) {
+ view.set('value', view.get('emptyValue'));
+ } else {
+ view.set('value', condition.value);
+ }
Em.run.next(function () {
view.showClearFilter();
// check if it is the last iteration
@@ -320,24 +324,33 @@ App.TableView = Em.View.extend(App.UserPref, {
* @param {String} type
*/
updateFilter: function (iColumn, value, type) {
+ this.saveFilterConditions(iColumn, value, type, false);
+ this.filtersUsedCalc();
+ this.filter();
+ },
+
+ /**
+ * save filter conditions to local storage
+ * @param iColumn {Number}
+ * @param value {String|Array}
+ * @param type {String}
+ * @param skipFilter {Boolean}
+ */
+ saveFilterConditions: function(iColumn, value, type, skipFilter) {
var filterCondition = this.get('filterConditions').findProperty('iColumn', iColumn);
+
if (filterCondition) {
filterCondition.value = value;
- }
- else {
+ filterCondition.skipFilter = skipFilter;
+ } else {
filterCondition = {
+ skipFilter: skipFilter,
iColumn: iColumn,
value: value,
type: type
};
this.get('filterConditions').push(filterCondition);
}
- this.saveFilterConditions();
- this.filtersUsedCalc();
- this.filter();
- },
-
- saveFilterConditions: function() {
App.db.setFilterConditions(this.get('controller.name'), this.get('filterConditions'));
},
http://git-wip-us.apache.org/repos/asf/ambari/blob/80b2a1f2/ambari-web/app/views/main/dashboard/config_history_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/dashboard/config_history_view.js b/ambari-web/app/views/main/dashboard/config_history_view.js
index b93a229..d302e69 100644
--- a/ambari-web/app/views/main/dashboard/config_history_view.js
+++ b/ambari-web/app/views/main/dashboard/config_history_view.js
@@ -24,23 +24,60 @@ App.MainConfigHistoryView = App.TableView.extend({
templateName: require('templates/main/dashboard/config_history'),
controllerBinding: 'App.router.mainConfigHistoryController',
+ filteringComplete: true,
+ timeOut: null,
content: function () {
return this.get('controller.content');
}.property('controller.content'),
+ pageContent: function () {
+ var content = this.get('filteredContent');
+ if (content.length > this.get('endIndex') - this.get('startIndex') + 1) {
+ content = content.slice(0, this.get('endIndex') - this.get('startIndex') + 1);
+ }
+ return content.sort(function (a, b) {
+ return a.get('index') - b.get('index');
+ });
+ }.property('filteredCount'),
+
+ filteredCount: function () {
+ return this.get('controller.filteredCount');
+ }.property('controller.filteredCount'),
+
+ totalCount: function () {
+ //TODO change to totalCount when property provided by API
+ return this.get('controller.filteredCount');
+ }.property('controller.filteredCount'),
/**
* return filtered number of all content number information displayed on the page footer bar
* @returns {String}
*/
filteredContentInfo: function () {
- return this.t('hosts.filters.filteredHostsInfo').format(this.get('filteredCount'), this.get('content.length'));
+ return this.t('hosts.filters.filteredHostsInfo').format(this.get('filteredCount'), this.get('totalCount'));
}.property('filteredCount', 'totalCount'),
+ /**
+ * synchronize properties of view with controller to generate query parameters
+ */
+ updatePagination: function () {
+ if (!Em.isNone(this.get('displayLength'))) {
+ App.db.setDisplayLength(this.get('controller.name'), this.get('displayLength'));
+ this.get('controller.paginationProps').findProperty('name', 'displayLength').value = this.get('displayLength');
+ }
+ if (!Em.isNone(this.get('startIndex'))) {
+ App.db.setStartIndex(this.get('controller.name'), this.get('startIndex'));
+ this.get('controller.paginationProps').findProperty('name', 'startIndex').value = this.get('startIndex');
+ }
+
+ this.refresh();
+ },
didInsertElement: function () {
+ this.addObserver('startIndex', this, 'updatePagination');
+ this.addObserver('displayLength', this, 'updatePagination');
this.set('controller.isPolling', true);
- this.get('controller').load();
+ this.refresh();
},
/**
@@ -59,7 +96,7 @@ App.MainConfigHistoryView = App.TableView.extend({
}),
modifiedSort: sort.fieldView.extend({
column: 2,
- name: 'createTime',
+ name: 'appliedTime',
displayName: Em.I18n.t('dashboard.configHistory.table.modified.title')
}),
authorSort: sort.fieldView.extend({
@@ -73,13 +110,14 @@ App.MainConfigHistoryView = App.TableView.extend({
displayName: Em.I18n.t('common.notes')
}),
- versionFilterView: filters.createSelectView({
+ serviceFilterView: filters.createSelectView({
column: 1,
fieldType: 'filter-input-width',
- content: ['All'],
- valueBinding: "controller.filterObject.version",
+ content: function () {
+ return ['All'].concat(App.Service.find().mapProperty('serviceName'));
+ }.property('App.router.clusterController.isLoaded'),
onChangeValue: function () {
- this.get('parentView').updateFilter(this.get('column'), this.get('value'), 'select');
+ this.get('parentView').updateFilter(this.get('column'), this.get('actualValue'), 'select');
},
emptyValue: Em.I18n.t('common.all')
}),
@@ -87,11 +125,13 @@ App.MainConfigHistoryView = App.TableView.extend({
modifiedFilterView: filters.createSelectView({
column: 2,
fieldType: 'filter-input-width',
- content: ['Any'],
- valueBinding: "controller.filterObject.modified",
- onChangeValue: function () {
- this.get('parentView').updateFilter(this.get('column'), this.get('value'), 'select');
- }
+ content: ['Any', 'Past 1 hour', 'Past 1 Day', 'Past 2 Days', 'Past 7 Days', 'Past 14 Days', 'Past 30 Days', 'Custom'],
+ valueBinding: "controller.modifiedFilter.optionValue",
+ startTimeBinding: "controller.modifiedFilter.actualValues.startTime",
+ endTimeBinding: "controller.modifiedFilter.actualValues.endTime",
+ onTimeChange: function () {
+ this.get('parentView').updateFilter(this.get('column'), [this.get('startTime'), this.get('endTime')], 'range');
+ }.observes('startTime')
}),
authorFilterView: filters.createTextView({
@@ -110,11 +150,34 @@ App.MainConfigHistoryView = App.TableView.extend({
}
}),
+ updateFilter: function (iColumn, value, type) {
+ var self = this;
+
+ this.set('controller.resetStartIndex', false);
+ this.saveFilterConditions(iColumn, value, type, false);
+ if (!this.get('filteringComplete')) {
+ clearTimeout(this.get('timeOut'));
+ this.set('timeOut', setTimeout(function () {
+ self.updateFilter(iColumn, value, type);
+ }, this.get('filterWaitingTime')));
+ } else {
+ clearTimeout(this.get('timeOut'));
+ this.set('controller.resetStartIndex', true);
+ this.refresh();
+ }
+ },
+
/**
* sort content
*/
refresh: function () {
- this.sortContent();
+ var self = this;
+
+ this.set('filteringComplete', false);
+ this.get('controller').loadHistoryToModel().done(function(){
+ self.set('filteringComplete', true);
+ self.propertyDidChange('pageContent');
+ });
},
/**
@@ -122,12 +185,13 @@ App.MainConfigHistoryView = App.TableView.extend({
* @type {Array}
*/
colPropAssoc: function () {
- var associations = [];
- associations[1] = 'serviceVersion';
- associations[2] = 'createTime';
- associations[3] = 'author';
- associations[4] = 'notes';
- return associations;
- }.property()
+ return this.get('controller.colPropAssoc');
+ }.property('controller.colPropAssoc'),
+
+ resetStartIndex: function () {
+ if (this.get('controller.resetStartIndex') && this.get('filteredCount') > 0) {
+ this.set('startIndex', 1);
+ }
+ }.observes('controller.resetStartIndex')
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/80b2a1f2/ambari-web/app/views/main/host.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/host.js b/ambari-web/app/views/main/host.js
index d267a2b..e9c90fd 100644
--- a/ambari-web/app/views/main/host.js
+++ b/ambari-web/app/views/main/host.js
@@ -85,11 +85,6 @@ App.MainHostView = App.TableView.extend(App.TableServerProvider, {
}.property('filteredCount'),
/**
- * Stub function
- */
- updatePaging: function () {},
-
- /**
* flag to toggle displaying selected hosts counter
*/
showSelectedFilter: function () {