Return-Path: X-Original-To: apmail-ambari-commits-archive@www.apache.org Delivered-To: apmail-ambari-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 0CE9F102C4 for ; Mon, 3 Feb 2014 18:05:50 +0000 (UTC) Received: (qmail 83620 invoked by uid 500); 3 Feb 2014 18:05:49 -0000 Delivered-To: apmail-ambari-commits-archive@ambari.apache.org Received: (qmail 83573 invoked by uid 500); 3 Feb 2014 18:05:49 -0000 Mailing-List: contact commits-help@ambari.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: ambari-dev@ambari.apache.org Delivered-To: mailing list commits@ambari.apache.org Received: (qmail 83562 invoked by uid 99); 3 Feb 2014 18:05:49 -0000 Received: from tyr.zones.apache.org (HELO tyr.zones.apache.org) (140.211.11.114) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 03 Feb 2014 18:05:49 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id C2C309181F1; Mon, 3 Feb 2014 18:05:48 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: alexantonenko@apache.org To: commits@ambari.apache.org Message-Id: X-Mailer: ASF-Git Admin Mailer Subject: git commit: AMBARI-4511. Jobs: implement filtering/sorting/limit on Apps table (alexantonenko) Date: Mon, 3 Feb 2014 18:05:48 +0000 (UTC) Updated Branches: refs/heads/trunk 337248d1d -> 0064670d4 AMBARI-4511. Jobs: implement filtering/sorting/limit on Apps table (alexantonenko) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/0064670d Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/0064670d Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/0064670d Branch: refs/heads/trunk Commit: 0064670d46b7f88861b791e657a9b8b0d44f1981 Parents: 337248d Author: Alex Antonenko Authored: Mon Feb 3 19:58:36 2014 +0200 Committer: Alex Antonenko Committed: Mon Feb 3 19:58:36 2014 +0200 ---------------------------------------------------------------------- ambari-web/app/controllers.js | 2 - .../app/controllers/main/jobs_controller.js | 38 ++-- ambari-web/app/styles/apps.less | 133 ++++++++++++-- ambari-web/app/templates/main/jobs.hbs | 26 +-- ambari-web/app/views/common/filter_view.js | 9 +- ambari-web/app/views/main/jobs_view.js | 178 ++++++++++++------- 6 files changed, 266 insertions(+), 120 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/0064670d/ambari-web/app/controllers.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers.js b/ambari-web/app/controllers.js index 02bcbf4..95f8b6b 100644 --- a/ambari-web/app/controllers.js +++ b/ambari-web/app/controllers.js @@ -110,7 +110,6 @@ require('controllers/main/charts/heatmap'); require('controllers/main/apps_controller'); require('controllers/main/jobs_controller'); require('controllers/main/jobs/hive_job_details_controller'); -require('controllers/main/apps_controller'); require('controllers/main/apps/item_controller'); require('controllers/main/mirroring_controller'); require('controllers/main/mirroring/edit_dataset_controller'); @@ -120,7 +119,6 @@ require('controllers/main/mirroring/targetClusterController'); require('controllers/main/mirroring/testConnection_controller'); require('controllers/main/mirroring/testConnectionResults_controller'); require('controllers/main/mirroring/manage_clusters_controller'); -require('controllers/main/jobs_controller'); require('controllers/wizard/slave_component_groups_controller'); require('controllers/wizard/step0_controller'); require('controllers/wizard/step1_controller'); http://git-wip-us.apache.org/repos/asf/ambari/blob/0064670d/ambari-web/app/controllers/main/jobs_controller.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers/main/jobs_controller.js b/ambari-web/app/controllers/main/jobs_controller.js index b5b8754..f6debd4 100644 --- a/ambari-web/app/controllers/main/jobs_controller.js +++ b/ambari-web/app/controllers/main/jobs_controller.js @@ -31,31 +31,19 @@ App.MainJobsController = Em.ArrayController.extend({ */ jobsLimit : -1, - - clearFilters: function () { - var obj=this.get("filterObject"); - obj.set("id",""); - obj.set("user",""); - obj.set("startTime",""); - obj.set("endTime",""); - }, - - //Filter object - - filterObject : Ember.Object.create({ - id:"", - user:"", - startTime:"", - endTime:"", - - - allFilterActivated:false, - filteredDisplayRecords:null, - - viewType:"all", - viewTypeClickEvent:false - - }), + /** + * List of users. + * Will be used for filtering in user column. + * Go to App.MainJobsView.userFilterView for more information + */ + users: function () { + return this.get('content').mapProperty("user").uniq().map(function(userName){ + return { + name: userName, + checked: false + }; + }); + }.property('content.length'), columnsName: Ember.ArrayController.create({ content: [ http://git-wip-us.apache.org/repos/asf/ambari/blob/0064670d/ambari-web/app/styles/apps.less ---------------------------------------------------------------------- diff --git a/ambari-web/app/styles/apps.less b/ambari-web/app/styles/apps.less index 0256c38..70d5372 100644 --- a/ambari-web/app/styles/apps.less +++ b/ambari-web/app/styles/apps.less @@ -16,7 +16,7 @@ * limitations under the License. */ -#apps, #jobs{ +#apps { td .red { color: red; @@ -35,21 +35,6 @@ } } - .jobs-type { - float: right; - margin-top: -24px; - } - - #filtered-jobs{ - float: left; - margin-top: 8px; - } - - .jobs_head{ - height: 30px; - } - - #filter_buttons a.selected{ cursor: default; } @@ -293,6 +278,122 @@ } } } + +#jobs { + + .jobs-type { + float: right; + margin-top: -24px; + } + + #filtered-jobs{ + float: left; + margin-top: 8px; + } + + .jobs_head{ + height: 30px; + } + + .page-bar { + border: 1px solid silver; + text-align:right; + div { + display: inline-block; + margin:0 10px; + } + .items-on-page { + label { + display:inline; + } + select { + margin-bottom: 4px; + margin-top: 4px; + width:70px; + } + } + .paging_two_button { + a { + padding:0 5px; + } + } + } + + .table { //margin-bottom: 0; + thead { //background: #EDF5FC; + } + th { + border-top: none; + } + th, td { + width: 82px; + border-left-width: 0; + } + + td:first-child, + th:first-child { + border-left-width: 1px; + } + + ul.filter-components { + padding: 5px 0; + li { + display: block; + padding: 3px 0 3px 5px; + line-height: 20px; + + label.checkbox { + padding-left: 3px; + } + + input[type="checkbox"] { + margin: 4px 4px 2px 2px; + } + } + &>li { + &>ul { + height: 250px; + margin-left: 0; + overflow-y: scroll; + } + } + } + .sorting_asc { + background: url(data:image/jpeg;base64,/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAZAAA/+4ADkFkb2JlAGTAAAAAAf/bAIQAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQICAgICAgICAgICAwMDAwMDAwMDAwEBAQEBAQECAQECAgIBAgIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMD/8AAEQgAEwATAwERAAIRAQMRAf/EAHgAAAMBAQAAAAAAAAAAAAAAAAAFCAYKAQACAQUAAAAAAAAAAAAAAAAABQMCBAYHCBAAAQUAAQMEAwAAAAAAAAAAAwECBAUGABESByExIghBMxQRAAIBAwMDAwUAAAAAAAAAAAECAwAEBRESBiExUUHhB2GBIhMU/9oADAMBAAIRAxEAPwDvA8k+Qc54sxGj32qlNi0ucrjTj/JqGlmROyJXQ2u/bOsZTmBExPd70/HXmQcW41lOX5+145h0L391KEHhR3Z28Ii6sx9AKgubiO1gaeU6Io19h9TUg/S/7eP+wia3NbBIFbuqiyn3VTCjIMArHHTJarEDGGiNU8vOKVsc7/VxBuGR3yV683X86/Cq/GpssrhP2S8emiSKRm1JS5VfyLH0WfQug7KwZR0CilWHy39++ObQTgkgeV9ux+xq9uc6U8pLfZzP6mClZpKWrvq1DilJAt4Mewh/0hRyBOsaUMoVKLvXtVU6t6+nL/HZTJYi4/rxU81tdbSu+N2Rtp7jcpB0OnUa9aoeOOVdsgDL4I1pFS+NPHmcsQ2+fw+UpLWOwwwWNVQ1kCaIcgaiONkmLGEZrDDXtcnXo5PfjC+5VybKWrWWSyF5cWbEEpJNI6kqdQSrMRqD1B9KjS2t423xoqt5AArb8QVPRwoo4UUcKK//2Q== ) no-repeat right 50%; + } + .sorting_desc { + background: url(data:image/jpeg;base64,/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAZAAA/+4ADkFkb2JlAGTAAAAAAf/bAIQAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQICAgICAgICAgICAwMDAwMDAwMDAwEBAQEBAQECAQECAgIBAgIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMD/8AAEQgAEwATAwERAAIRAQMRAf/EAIEAAAIDAQAAAAAAAAAAAAAAAAAGBwgJCgEBAAIDAQAAAAAAAAAAAAAAAAMFBAYHCBAAAAUDAwMFAAAAAAAAAAAAAQIDBAUABgcSNTYRFQgTZFUWZhEAAAQEAggGAwAAAAAAAAAAAAECAxEhBAYSMjFBYRMzFDQFUZFSYmMHJFRk/9oADAMBAAIRAxEAPwDv4oAKACgCKc1tMmusb3Eph6cSgsgx7fucEZxGRks2llGIGVWgVm8q1dt0+6ogKaapSgdNbQPXTqAdwsN602bopk3vTnUW24rduwccbU2S5E8Sm1JM92czSZwNOKUYDFrCqTp1corDUFMpEcYap+Ipb4P5O8n81y9xXXlG50yY+thR3AEivqFvRDmduvSUrhuLtrFNXqCFvJm1LAQ5RMuchB6gBy13f7+tP6lsOipuz2jSGdy1ZJeNzmXnEtU+pWFTikmbxyTEjgglKKZpMU3ZanudYtTtSr8dMoYSKKvKMte0aUV5YGxgoASbD2iQ4Tyi6uB7Rvz/AHD9R8r7/wBWr64uta6/pKfq+JwUZP5/1/hwCFjIeTMrLo0np93q2xDtVCJh/9k=) no-repeat right 50%; + } + .sorting { + background: url(data:image/jpeg;base64,/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAZAAA/+4ADkFkb2JlAGTAAAAAAf/bAIQAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQICAgICAgICAgICAwMDAwMDAwMDAwEBAQEBAQECAQECAgIBAgIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMD/8AAEQgAEwATAwERAAIRAQMRAf/EAGgAAAIDAQAAAAAAAAAAAAAAAAUHAAYICgEBAQAAAAAAAAAAAAAAAAAAAAEQAAEEAQIFAgcAAAAAAAAAAAECAwQFABEGIRI0NQcTFDFBMmNUZRYRAQEBAQAAAAAAAAAAAAAAAAABEUH/2gAMAwEAAhEDEQA/AO93cd/XbXpLC9tHQ1Dr46nljUBby/gzGZB+p+Q6QhA+ZOApfDnllW/ha1tv6Ee7iyH5kRlvlbTIqHndWkNJ0HO7XFQbWeJUkpUeOpySrZh65UUnyFUW1ztaexRmIbaPyzoLE6vg2UWW9GC1e0XHnsSGEqfQohCwApK9OIGuAjfBP9VuG0m39vGqINVUe4r2xF21TVsuXZOI9N9lMmLBYkttQ21auBKhqtSUngCMkW5xqjKiYASh6SR2Tulr2HpOvf6j9p+V9/mwDeB//9k=) no-repeat right 50%; + } + + div.view-wrapper { + .btn-group { + margin-bottom: 9px; + } + } + + a.ui-icon-circle-close { + float: right; + opacity: 0.2; + padding: 1px; + position: relative; + right: -8px; + margin-top: 6px; + z-index: 10; + &:hover { + opacity: 0.7; + } + } + .notActive { + a.ui-icon-circle-close { + visibility: hidden; + } + } + } +} + .btn-group button.single-btn-group{ -webkit-border-radius: 4px; border-radius: 4px; http://git-wip-us.apache.org/repos/asf/ambari/blob/0064670d/ambari-web/app/templates/main/jobs.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/main/jobs.hbs b/ambari-web/app/templates/main/jobs.hbs index d51034d..151e052 100644 --- a/ambari-web/app/templates/main/jobs.hbs +++ b/ambari-web/app/templates/main/jobs.hbs @@ -16,7 +16,7 @@ * limitations under the License. }} -
+
{{t menu.item.jobs}}
@@ -28,16 +28,18 @@
- +
- {{#view view.wrapSorting}} - {{#each controller.columnsName}} - {{#view view.parentView.sortingColumns contentBinding="this"}} - {{name}} - {{/view}} - {{/each}} + + {{#view view.sortView contentBinding="view.filteredContent"}} + {{view view.parentView.idSort}} + {{view view.parentView.userSort}} + {{view view.parentView.startTimeSort}} + {{view view.parentView.endTimeSort}} + {{view view.parentView.durationSort}} {{/view}} - + + @@ -51,7 +53,7 @@ {{else}} - {{#each job in content}} + {{#each job in view.pageContent}}
{{view view.jobsIdFilterView}} {{view view.userFilterView}} {{view view.startTimeFilterView}}{{t apps.filters.nothingToShow}}
{{unbound job.name}} @@ -76,10 +78,10 @@
- {{view.filteredJobs}} - {{t jobs.filtered.clear}} + {{view.filteredJobs}} - {{t jobs.filtered.clear}}
- +
http://git-wip-us.apache.org/repos/asf/ambari/blob/0064670d/ambari-web/app/views/common/filter_view.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/common/filter_view.js b/ambari-web/app/views/common/filter_view.js index 77d56a8..45f69df 100644 --- a/ambari-web/app/views/common/filter_view.js +++ b/ambari-web/app/views/common/filter_view.js @@ -370,6 +370,9 @@ module.exports = { var match = false; var timePassed = new Date().getTime() - rowValue; switch (rangeExp) { + case 'Past 1 hour': + match = timePassed <= 3600000; + break; case 'Past 1 Day': match = timePassed <= 86400000; break; @@ -436,7 +439,11 @@ module.exports = { case 'multiple': return function(origin, compareValue){ var options = compareValue.split(','); - var rowValue = origin.mapProperty('componentName').join(" "); + if(typeof (origin) === "string"){ + var rowValue = origin; + }else{ + var rowValue = origin.mapProperty('componentName').join(" "); + } var str = new RegExp(compareValue, "i"); for (var i = 0; i < options.length; i++) { if(!isGlobal) { http://git-wip-us.apache.org/repos/asf/ambari/blob/0064670d/ambari-web/app/views/main/jobs_view.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/main/jobs_view.js b/ambari-web/app/views/main/jobs_view.js index 93596c9..23aa64a 100644 --- a/ambari-web/app/views/main/jobs_view.js +++ b/ambari-web/app/views/main/jobs_view.js @@ -18,68 +18,83 @@ var App = require('app'); var filters = require('views/common/filter_view'); +var sort = require('views/common/sort_view'); -App.MainJobsView = Em.View.extend({ +App.MainJobsView = App.TableView.extend({ templateName: require('templates/main/jobs'), - showNumberOfJobs: Em.Select.extend({ - selected: '10', - content: ['10', '25', '50', '100', "250", "500"] + content: function () { + return this.get('controller.content'); + }.property('controller.content.length'), + + didInsertElement: function () { + this.set('filteredContent', this.get('controller.content')); + }, + + sortView: sort.wrapperView, + idSort: sort.fieldView.extend({ + column: 0, + name: 'id', + displayName: Em.I18n.t('jobs.column.id'), + type: 'string' + }), + userSort: sort.fieldView.extend({ + column: 1, + name: 'user', + displayName: Em.I18n.t('jobs.column.user'), + type: 'string' + }), + startTimeSort: sort.fieldView.extend({ + column: 2, + name: 'startTime', + displayName: Em.I18n.t('jobs.column.start.time'), + type: 'number' + }), + endTimeSort: sort.fieldView.extend({ + column: 3, + name: 'endTime', + displayName: Em.I18n.t('jobs.column.end.time'), + type: 'number' + }), + durationSort: sort.fieldView.extend({ + column: 4, + name: 'duration', + displayName: Em.I18n.t('jobs.column.duration'), + type: 'number' + }), + + /** + * Select View with list of "rows-per-page" options + * @type {Ember.View} + */ + rowsPerPageSelectView: Em.Select.extend({ + content: ['10', '25', '50', '100', "250", "500"], + change: function () { + this.get('parentView').saveDisplayLength(); + } }), + /** + * return filtered number of all content number information displayed on the page footer bar + * @returns {String} + */ filteredJobs: function () { - return Em.I18n.t('jobs.filtered.jobs').format(0,0); - }.property(), + return Em.I18n.t('jobs.filtered.jobs').format(this.get('filteredContent.length'), this.get('content').get('length')); + }.property('content.length', 'filteredContent.length'), /** * Filter-field for Jobs ID. * Based on filters library */ - jobsIdFilterView: filters.createTextView({ + /*jobsIdFilterView: filters.createTextView({ valueBinding: "controller.filterObject.id" - }), - - wrapSorting: Ember.View.extend({ - tagName: 'tr' - }), + }),*/ - sortingColumns: Ember.View.extend({ - tagName: 'th', - classNameBindings: ['class', 'widthClass'], - class: "sorting", - widthClass: "", - content: null, - defaultColumn: 8, - - didInsertElement: function () { - this.set("widthClass", "col" + this.get('content.index')); - if (this.get('content.index') == this.get('defaultColumn')) { - this.setControllerObj(this.content.index, "DESC"); - this.set("class", "sorting_desc"); - } - }, - click: function (event) { - console.log(this.get('class')); - if (this.get('class') == "sorting") { - this.resetSortClass(); - this.setControllerObj(this.get('content.index'), "ASC"); - this.set("class", "sorting_asc"); - } else if (this.get('class') == "sorting_asc") { - this.setControllerObj(this.get('content.index'), "DESC"); - this.set("class", "sorting_desc"); - } else if (this.get('class') == "sorting_desc") { - this.setControllerObj(this.get('content.index'), "ASC"); - this.set("class", "sorting_asc"); - } - }, - resetSortClass: function () { - this.get("parentView.childViews").map(function (a, e) { - a.get("childViews")[0].set("class", "sorting") - }); - }, - setControllerObj: function (col, dir) { - this.set("controller.filterObject.iSortCol_0", col); - this.set("controller.filterObject.sSortDir_0", dir); + jobsIdFilterView: filters.createTextView({ + column: 0, + fieldType: 'width70', + onChangeValue: function(){ + this.get('parentView').updateFilter(this.get('column'), this.get('value'), 'string'); } }), @@ -88,6 +103,9 @@ App.MainJobsView = Em.View.extend({ * Based on filters library */ userFilterView: filters.createComponentView({ + + column: 1, + /** * Inner FilterView. Used just to render component. Value bind to mainview.value property * Base methods was implemented in filters.componentFieldView @@ -97,14 +115,7 @@ App.MainJobsView = Em.View.extend({ usersBinding: 'controller.users', - allComponentsChecked:false, - toggleAllComponents:function () { - var checked = this.get('allComponentsChecked'); - this.get('users').setEach('checked', checked); - }.observes('allComponentsChecked'), - clearFilter:function() { - this.set('allComponentsChecked', false); this.get('users').setEach('checked', false); this._super(); }, @@ -113,10 +124,30 @@ App.MainJobsView = Em.View.extend({ this._super(); var chosenUsers = this.get('users').filterProperty('checked', true).mapProperty('name'); this.set('value', chosenUsers.toString()); - } + }, + + /** + * Verify that checked checkboxes are equal to value + */ + checkUsers: function() { + var users = this.get('value').split(','); + var self = this; + if (users) { + users.forEach(function(userName) { + var u = self.get("users").findProperty('name', userName); + if (u) { + if (!u.checked) { + u.checked = true; + } + } + }); + } + }.observes('users.length') }), - valueBinding: 'controller.filterObject.user' + onChangeValue: function(){ + this.get('parentView').updateFilter(this.get('column'), this.get('value'), 'multiple'); + } }), /** @@ -125,17 +156,36 @@ App.MainJobsView = Em.View.extend({ */ startTimeFilterView: filters.createSelectView({ fieldType: 'input-medium', - valueBinding: "controller.filterObject.startTime", - content: ['Any', 'Past 1 hour', 'Past 1 Day', 'Past 2 Days', 'Past 7 Days', 'Past 14 Days', 'Past 30 Days', 'Custom'] + column: 2, + content: ['Any', 'Past 1 hour', 'Past 1 Day', 'Past 2 Days', 'Past 7 Days', 'Past 14 Days', 'Past 30 Days'], + onChangeValue: function () { + this.get('parentView').updateFilter(this.get('column'), this.get('value'), 'date'); + } }), /** - * Filter-field for Start Time. + * Filter-field for End Time. * Based on filters library */ endTimeFilterView: filters.createSelectView({ fieldType: 'input-medium', - valueBinding: "controller.filterObject.endTime", - content: ['Any', 'Custom'] - }) + column: 3, + content: ['Any'], + onChangeValue: function () { + this.get('parentView').updateFilter(this.get('column'), this.get('value'), 'date'); + } + }), + + /** + * associations between content (jobs list) property and column index + */ + colPropAssoc: function () { + var associations = []; + associations[0] = 'id'; + associations[1] = 'user'; + associations[2] = 'startTime'; + associations[3] = 'endTime'; + return associations; + }.property() + })