123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464 |
- /**
- * 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');
- App.MainJobsController = Em.Controller.extend({
- /*
- * https://github.com/emberjs/ember.js/issues/1221 prevents this controller
- * from being an Ember.ArrayController. Doing so will keep the UI flashing
- * whenever any of the 'sortProperties' or 'sortAscending' properties are set.
- *
- * To bypass this issue this controller will be a regular controller. Also,
- * for memory-leak issues and sorting purposes, we are decoupling the backend
- * model and the UI model. There will be simple Ember POJOs for the UI which
- * will be periodically updated from backend Jobs model.
- */
-
- name:'mainJobsController',
- /**
- * Unsorted ArrayProxy
- */
- content: App.HiveJob.find(),
-
- /**
- * 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: ''
- },
- lastJobID: '',
- hasNewJobs: false,
- loaded : false,
- loading : false,
- resetPagination: false,
- loadJobsTimeout: null,
- loadTimeout: null,
- jobsUpdateInterval: 6000,
- jobsUpdate: null,
- sortingColumn: null,
- sortProperty: 'id',
- sortAscending: true,
- sortingDone: true,
- sortingColumnObserver: function () {
- if(this.get('sortingColumn')){
- this.set('sortProperty', this.get('sortingColumn').get('name'));
- this.set('sortAscending', this.get('sortingColumn').get('status') == "sorting_desc" ? false : true );
- }
- }.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 self = this;
- var interval = setInterval(function () {
- App.router.get(controllerName)[funcName]();
- }, this.jobsUpdateInterval);
- this.set('jobsUpdate', interval);
- },
- totalOfJobs: 0,
- setTotalOfJobs: function () {
- if(this.get('totalOfJobs') < this.get('content.length')){
- this.set('totalOfJobs', this.get('content.length'));
- }
- }.observes('content.length'),
- filterObject: Ember.Object.create({
- id: "",
- isIdFilterApplied: false,
- jobsLimit: 10,
- user: "",
- windowStart: "",
- windowEnd: "",
- nextFromId: "",
- backFromId: "",
- fromTs: "",
- isAnyFilterApplied: false,
- onApplyIdFilter: function () {
- if(this.get('id') == ""){
- this.set('isIdFilterApplied', false);
- }else{
- this.set('isIdFilterApplied', true);
- }
- }.observes('id'),
- /**
- * Direct binding to startTime filter field
- */
- 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,
- 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 () {
- var self = this;
- var windowEnd = "";
- var 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 false;
- }
- 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
- })
- });
- },
- 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'));
- }
- },
- /**
- * Create link for server request
- * @return {String}
- */
- createJobsFiltersLink: function() {
- var link = "?fields=events,primaryfilters,otherinfo";
- var numberOfAppliedFilters = 0;
- if(this.get("id") !== "") {
- link = "/" + this.get("id") + link;
- numberOfAppliedFilters++;
- }
- link += "&limit=" + (parseInt(this.get("jobsLimit")) + 1);
- if(this.get("user") !== ""){
- link += "&primaryFilter=user:" + this.get("user");
- numberOfAppliedFilters++;
- }
- if(this.get("backFromId") != ""){
- link += "&fromId=" + this.get("backFromId");
- }
- if(this.get("nextFromId") != ""){
- link += "&fromId=" + this.get("nextFromId");
- }
- if(this.get("fromTs") != ""){
- link += "&fromTs=" + this.get("fromTs");
- }
- 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++;
- }
- if(numberOfAppliedFilters > 0){
- this.set('isAnyFilterApplied', true);
- }else{
- this.set('isAnyFilterApplied', false);
- }
- return link;
- }
- }),
- 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 }
- ]
- }),
- lastIDSuccessCallback: function(data, jqXHR, textStatus) {
- var lastReceivedID = data.entities[0].entity;
- if(this.get('lastJobID') == '') {
- this.set('lastJobID', lastReceivedID);
- } else if (this.get('lastJobID') !== lastReceivedID) {
- this.set('lastJobID', lastReceivedID);
- this.set('hasNewJobs', true);
- }
- },
- lastIDErrorCallback: function(data, jqXHR, textStatus) {
- console.debug(jqXHR);
- },
- loadJobs : function() {
- var self = this;
- var timeout = this.get('loadTimeout');
- var yarnService = App.YARNService.find().objectAt(0);
- if (yarnService != null) {
- this.set('loading', true);
- var historyServerHostName = yarnService.get('appTimelineServerNode.hostName');
- var filtersLink = this.get('filterObject').createJobsFiltersLink();
- var hiveQueriesUrl = App.testMode ? "/data/jobs/hive-queries.json" : "/proxy?url=http://" + historyServerHostName
- + ":" + yarnService.get('ahsWebPort') + "/ws/v1/timeline/HIVE_QUERY_ID" + filtersLink;
- App.ajax.send({
- name: 'jobs.lastID',
- sender: self,
- data: {
- historyServerHostName: historyServerHostName,
- ahsWebPort: yarnService.get('ahsWebPort')
- },
- success: 'lastIDSuccessCallback',
- error : 'lastIDErrorCallback'
- }),
- App.HttpClient.get(hiveQueriesUrl, App.hiveJobsMapper, {
- complete : function(data, jqXHR, textStatus) {
- self.set('loading', false);
- if(self.get('loaded') == false || self.get('resetPagination') == true){
- self.initializePagination();
- self.set('resetPagination', false);
- }
- self.set('loaded', true);
- }
- }, function (jqXHR, textStatus) {
- App.hiveJobsMapper.map({entities : []});
- });
- }else{
- clearTimeout(timeout);
- timeout = setTimeout(function(){
- self.loadJobs();
- }, 300);
- }
- },
- initializePagination: function() {
- var back_link_IDs = this.get('navIDs.backIDs.[]');
- if(!back_link_IDs.contains(App.HiveJob.find().objectAt(0).get('id'))) {
- back_link_IDs.push(App.HiveJob.find().objectAt(0).get('id'));
- }
- this.set('filterObject.backFromId', App.HiveJob.find().objectAt(0).get('id'));
- this.get('filterObject').set('fromTs', App.get('currentServerTime'));
- },
- 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)) {
- back_link_IDs.push(lastBackID);
- }
- this.set('navIDs.backIDs.[]', back_link_IDs);
- this.set("filterObject.nextFromId", this.get('navIDs.nextID'));
- this.set('navIDs.nextID', '');
- this.loadJobs();
- },
- navigateBack: function() {
- this.set("filterObject.nextFromId", '');
- var back_link_IDs = this.get('navIDs.backIDs.[]');
- back_link_IDs.pop();
- var lastBackID = back_link_IDs[back_link_IDs.length - 1]
- this.set('navIDs.backIDs.[]', back_link_IDs);
- this.set("filterObject.backFromId", lastBackID);
- this.loadJobs();
- },
- refreshLoadedJobs : function() {
- var timeout = this.get('loadJobsTimeout');
- var self = this;
- clearTimeout(timeout);
- timeout = setTimeout(function(){
- self.loadJobs();
- }, 300);
- this.set('loadJobsTimeout', timeout);
- }.observes(
- 'filterObject.id',
- 'filterObject.jobsLimit',
- 'filterObject.user',
- 'filterObject.windowStart',
- 'filterObject.windowEnd'
- )
- })
|