define([ 'view/base', 'view/deletemonitor', 'model/monitor' ], function( BaseView, DeleteMonitorView, JobModel ){ var ExpandedMonitorView = BaseView.extend({ events : { 'click .name-save' : 'updateMonitorName', 'click .schedule-tab' : '_setExpandedViewHeight', 'change #selectPreviousError' : '_setErrorDropDown' }, subscriptions : { 'view:dashboard:init' : 'exit', 'view:deletemonitor:delete' : 'deleteMonitor' }, initialize : function(options) { _.bindAll(this); var self = this; this.user = options.user; this.router = options.router; this.templar = options.templar; // init delete monitor view this.deleteMonitorView = new DeleteMonitorView({ 'el' : $('.delete-monitor-wrap'), 'templar' : this.templar }); // use debounce to throttle resize events and set the height when // the viewport changes. var resize = _.debounce(this._setExpandedViewHeight, 500); // Add the event listener $(window).resize(resize); }, render : function(id, categories, categoryId, dashboardId) { this.monitorId = id; this.categories = categories; this.categoryId = categoryId; this.dashboardId = dashboardId; this.initMonitor(); }, /** * ExpandedMonitorView#initMonitor(model) * - model (Object): job (monitor) backbone model object * * **/ initMonitor : function() { var self = this; // retrieve monitor model & graph data self.getMonitor(self.monitorId, function(result) { // make sure update has a reference to the instance and model // at the time of editing/updating self.model = result; _.bind(self.updateMonitor, self, self.model); _.each(self.categories, function(category) { if (category.id === self.model.get('dashboardId')) { category.selected = true; } else { category.selected = false; } }); self.getGraphData(self.monitorId, function(result) { self._initErrorsList(function(errors) { self.templar.render({ path : 'expandedmonitor', el : self.$el, data : { 'monitor' : self.model.toJSON(), 'errors' : errors, 'alerts' : errors, 'output' : self.model.get('output'), 'categories' : self.categories } }); self.$monitor = self.$el.find('.expanded-monitor'); //edit-monitor-wrap container element self.$el.html( self.$monitor ); // add events to the view buttons in the alert window self._setAlertsHistory(); // setup the graph area self.chart = self.initGraph( self.$monitor.find('.graph')[0]); // set error state self._setErrorState(); self.updateGraph(self.model, function(output) { self._initializeCodeMirror(); self._initializeDatePicker('.input-from-date'); self._setErrorDropDown(); self._setScheduleData(); self._setEditNameField(); self.$el.find('.save-changes').click({'model' : self.model}, self.updateMonitor); self.$el.find('.cancel-changes').click(function() { self.exit(); }); self.$el.find('.test-in-graph button').click({ 'model' : new JobModel(), 'output' : output }, self.testMonitor, self); // finally open up the edit monitor widget self.open(); }, self.formattedGraphData); // inline help self.setHelp(); // dynamically set the heights to maximum screen utilization self._setExpandedViewHeight(); }, self.model); }); }); }, getGraphData : function(monitorId, cb) { var self = this; $.ajax({ url : '/jobs/' + monitorId + '/data', success : function(result) { if ( result.graph_data ) { self.formattedGraphData = self.formatGraphData( result.graph_data ); } // always call the callback function // it loads the view if ( !_.isUndefined(cb) ) cb(result); }, error : function(result) { if ( !_.isUndefined(cb) ) { cb(result); } } }); }, getMonitor : function(monitorId, cb) { var self = this; self.model = new JobModel({ id : monitorId }); self.model.fetch({ success : function(result) { if ( !_.isUndefined(cb) ) { cb(result); } } }); }, getErrorStatus : function(status) { var self = this, error = false; switch ( status ) { case 'error' : error = true; break; case 'failed' : error = true; break; case 'graphite_error' : error = true; break; case 'graphite_metric_error' : error = true; break; case 'security_error' : error = true; break; } return error; }, setHelp : function() { var self = this, $content = ''; $alertContent = ''; $.ajax({ url : '/help/quick.html', async : false, success : function( response ) { $content = response; } }); $.ajax({ url : '/help/alert.html', async : false, success : function( response ) { $alertContent = response; } }); self.$el.find('.help:nth-child(2)').tooltip({ trigger : 'click', html : true, placement : 'right', delay : { show : 100, hide : 200 }, title : $content }); self.$el.find('.help:nth-child(1)').tooltip({ trigger : 'click', html : true, placement : 'left', delay : { show : 100, hide : 200 }, title : $alertContent }); }, /** * ExpandedMonitorView#open() * * **/ open : function() { this.$el.addClass('active'); //publish for other views can update Backbone.Mediator.pub('view:expandedmonitor:open', { 'nav' : { 'back' : true } }); // set route for hotlinking purposes this.router.navigate('dash/' + this.dashboardId + '/expand/' + this.model.get('id')); }, /** * ExpandedMonitorView#exit() * * **/ exit : function(monitor) { var self = this, monitor = ( monitor ) ? monitor : null; self.$el.removeClass('active'); // set route for hotlinking purposes if(self.model) { self.router.navigate('dash/' + self.model.get('dashboardId')); } // fire event that expandedmonitor is exiting Backbone.Mediator.pub('view:expandedmonitor:exit', { status : 'delete' }); }, /** * ExpandedMonitorView#updateGraph(model, cb) * - model (Object): job (monitor) backbone model object * - cb (Function): callback function * **/ updateGraph : function(model, cb, graphData) { var self = this; if(graphData) { self.renderGraphData(self.chart, graphData); if(typeof cb === 'function') { cb(); } } else { $.ajax({ url : '/monitor.json', type : 'POST', data : model.toJSON(), success : function(result) { if ( result.graph_data ) { var formattedGraphData = self.formatGraphData( result.graph_data ); self.renderGraphData(self.chart, formattedGraphData); self.$el.find('textarea.output-view').val(result.output); } if(typeof cb === 'function') { cb(result.output); } } }); } }, /** * ExpandedMonitorView#testMonitor(e) * * **/ testMonitor : function(e) { var self = this, monitor = e.data.model, output = e.data.output, $testBtn = $(e.target); // set button state $testBtn.button('loading'); monitor = self._setMetrics(monitor); monitor = self._setSchedule(monitor); // update to the output view for testing self.$el.find('textarea.output-view').val(output); self.$el.find('.output-tab').tab('show'); self.updateGraph(monitor, function() { $testBtn.button('reset'); }); }, /** * ExpandedMonitorView#viewErrorInGraph(e) * * **/ viewErrorInGraph : function(e) { var self = this, monitor = e.data.model, output = e.data.output, toDate = e.data.toDate; monitor.set('toDate', toDate); // viewError in graph gets the from // toDate field not from the html field monitor = self._setMetrics(monitor, true); monitor = self._setSchedule(monitor); // otherwise update to the output view for testing self.$el.find('textarea.output-view').val(output); self.$el.find('.output-tab').tab('show'); self.updateGraph(monitor); }, /** * ExpandedMonitorView#updateMonitor(e) * * **/ updateMonitor : function(e) { var self = this, monitor = e.data.model, test = e.data.test, toDate = e.data.toDate, output = e.data.output; monitor = self._setMetrics(monitor); monitor = self._setSchedule(monitor); monitor = self._setSettings(monitor); monitor.save(null, { success : function(model, response, options) { Backbone.Mediator.pub('view:expandedmonitor:save', { 'model' : self.model, 'message' : "The monitor '" + model.get('name') + "' was saved.", 'attention' : 'Monitor Saved!', 'status' : 'success' }); // quit out of the edit monitor view self.exit(monitor); self.updateGraph(monitor); }, error : function(model, xhr, options) { Backbone.Mediator.pub('view:expandedmonitor:save', { 'model' : self.model, 'message' : "The monitor '" + model.get('name') + "' caused an error on saving, please try again.", 'attention' : 'Monitor Saved Error!', 'status' : 'error' }); } }); }, /** * ExpandedMonitorView#deleteMonitor(e) * * **/ deleteMonitor : function() { var self = this; self.model.destroy({ success : function(model, response) { Backbone.Mediator.pub('view:expandedmonitor:delete', { 'model' : self.model, 'message' : "The monitor '" + model.get('name') + "' was removed from the current dashboard.", 'attention' : 'Monitor Deleted!' }); }, error : function(model, response) { Backbone.Mediator.pub('view:expandedmonitor:delete', { 'model' : self.model, 'message' : "The monitor '" + model.get('name') + "' produced an error during the process of deletion.", 'attention' : 'Monitor Delete Error!', 'status' : 'error' }); } }); self.exit(); }, /** * ExpandedMonitorView#updateMonitorName() */ updateMonitorName : function() { var self = this; var $nameField = self.$el.find('.name-field'), previousName = $nameField.prev().html(); self.model.set({ 'name' : $nameField.find('input').val() }); $nameField.prev().html( self.model.get('name') ); $nameField.hide(); $nameField.prev().show(); }, /** * ExpandedMonitorView#resize() */ resize : function() { var self = this; return _.debounce(self._setExpandedViewHeight, 500); }, /** * ExpandedMonitorView#destructor() */ destructor : function() { var self = this, $prevSibling = self.$el.prev(); // clean up nested views self.deleteMonitorView.destructor(); // unsubscribe from mediator channels self.destroySubscriptions(); self.remove(); self.unbind(); self.off(); $prevSibling.after("