/* * Display log entries in a panel with scrollbar * The log entries are automatically refreshed via a background task, * with newest entries comming at the bottom */ Ext.define('Proxmox.panel.JournalView', { extend: 'Ext.panel.Panel', xtype: 'proxmoxJournalView', numEntries: 500, lineHeight: 16, scrollToEnd: true, controller: { xclass: 'Ext.app.ViewController', updateParams: function() { var me = this; var viewModel = me.getViewModel(); var since = viewModel.get('since'); var until = viewModel.get('until'); since.setHours(0, 0, 0, 0); until.setHours(0, 0, 0, 0); until.setDate(until.getDate()+1); me.getView().loadTask.delay(200, undefined, undefined, [ false, false, Ext.Date.format(since, "U"), Ext.Date.format(until, "U") ]); }, scrollPosBottom: function() { var view = this.getView(); var pos = view.getScrollY(); var maxPos = view.getScrollable().getMaxPosition().y; return maxPos - pos; }, scrollPosTop: function() { var view = this.getView(); return view.getScrollY(); }, updateScroll: function(livemode, num, scrollPos, scrollPosTop) { var me = this; var view = me.getView(); if (!livemode) { setTimeout(function() { view.scrollTo(0, 0); }, 10); } else if (view.scrollToEnd && scrollPos <= 0) { setTimeout(function() { view.scrollTo(0, Infinity); }, 10); } else if (!view.scrollToEnd && scrollPosTop < 20*view.lineHeight) { setTimeout(function() { view.scrollTo(0, num*view.lineHeight + scrollPosTop); }, 10); } }, updateView: function(lines, livemode, top) { var me = this; var view = me.getView(); var viewmodel = me.getViewModel(); if (viewmodel.get('livemode') !== livemode) { return; // we switched mode, do not update the content } var contentEl = me.lookup('content'); // save old scrollpositions var scrollPos = me.scrollPosBottom(); var scrollPosTop = me.scrollPosTop(); var newend = lines.shift(); var newstart = lines.pop(); var num = lines.length; var text = lines.map(Ext.htmlEncode).join('
'); if (!livemode) { if (num) { view.content = text; } else { view.content = 'nothing logged or no timespan selected'; } } else { // update content if (top && num) { view.content = view.content ? text + '
' + view.content : text; } else if (!top && num) { view.content = view.content ? view.content + '
' + text : text; } // update cursors if (!top || !view.startcursor) { view.startcursor = newstart; } if (top || !view.endcursor) { view.endcursor = newend; } } contentEl.update(view.content); me.updateScroll(livemode, num, scrollPos, scrollPosTop); }, doLoad: function(livemode, top, since, until) { var me = this; if (me.running) { me.requested = true; return; } me.running = true; var view = me.getView(); var params = { lastentries: view.numEntries || 500, }; if (livemode) { if (!top && view.startcursor) { params = { startcursor: view.startcursor }; } else if (view.endcursor) { params.endcursor = view.endcursor; } } else { params = { since: since, until: until }; } Proxmox.Utils.API2Request({ url: view.url, params: params, waitMsgTarget: (!livemode) ? view : undefined, method: 'GET', success: function(response) { Proxmox.Utils.setErrorMask(me, false); var lines = response.result.data; me.updateView(lines, livemode, top); me.running = false; if (me.requested) { me.requested = false; view.loadTask.delay(200); } }, failure: function(response) { var msg = response.htmlStatus; Proxmox.Utils.setErrorMask(me, msg); me.running = false; if (me.requested) { me.requested = false; view.loadTask.delay(200); } } }); }, onScroll: function(x, y) { var me = this; var view = me.getView(); var viewmodel = me.getViewModel(); var livemode = viewmodel.get('livemode'); if (!livemode) { return; } if (me.scrollPosTop() < 20*view.lineHeight) { view.scrollToEnd = false; view.loadTask.delay(200, undefined, undefined, [true, true]); } else if (me.scrollPosBottom() <= 1) { view.scrollToEnd = true; } }, init: function(view) { var me = this; if (!view.url) { throw "no url specified"; } var viewmodel = me.getViewModel(); var viewModel = this.getViewModel(); var since = new Date(); since.setDate(since.getDate() - 3); viewModel.set('until', new Date()); viewModel.set('since', since); me.lookup('content').setStyle('line-height', view.lineHeight + 'px'); view.loadTask = new Ext.util.DelayedTask(me.doLoad, me, [true, false]); me.updateParams(); view.task = Ext.TaskManager.start({ run: function() { if (!view.isVisible() || !view.scrollToEnd || !viewmodel.get('livemode')) { return; } if (me.scrollPosBottom() <= 1) { view.loadTask.delay(200, undefined, undefined, [true, false]); } }, interval: 1000 }); }, onLiveMode: function() { var me = this; var view = me.getView(); delete view.startcursor; delete view.endcursor; delete view.content; me.getViewModel().set('livemode', true); view.scrollToEnd = true; me.updateView([], true, false); }, onTimespan: function() { var me = this; me.getViewModel().set('livemode', false); me.updateView([], false); } }, onDestroy: function() { var me = this; me.loadTask.cancel(); Ext.TaskManager.stop(me.task); delete me.content; }, // for user to initiate a load from outside requestUpdate: function() { var me = this; me.loadTask.delay(200); }, viewModel: { data: { livemode: true, until: null, since: null } }, layout: 'auto', bodyPadding: 5, scrollable: { x: 'auto', y: 'auto', listeners: { // we have to have this here, since we cannot listen to events // of the scroller in the viewcontroller (extjs bug?), nor does // the panel have a 'scroll' event' scroll: { fn: function(scroller, x, y) { var controller = this.component.getController(); if (controller) { // on destroy, controller can be gone controller.onScroll(x,y); } }, buffer: 200 }, } }, tbar: { items: [ '->', { xtype: 'segmentedbutton', items: [ { text: gettext('Live Mode'), bind: { pressed: '{livemode}' }, handler: 'onLiveMode', }, { text: gettext('Select Timespan'), bind: { pressed: '{!livemode}' }, handler: 'onTimespan', } ] }, { xtype: 'box', bind: { disabled: '{livemode}' }, autoEl: { cn: gettext('Since') + ':' } }, { xtype: 'datefield', name: 'since_date', reference: 'since', format: 'Y-m-d', bind: { disabled: '{livemode}', value: '{since}', maxValue: '{until}' } }, { xtype: 'box', bind: { disabled: '{livemode}' }, autoEl: { cn: gettext('Until') + ':' } }, { xtype: 'datefield', name: 'until_date', reference: 'until', format: 'Y-m-d', bind: { disabled: '{livemode}', value: '{until}', minValue: '{since}' } }, { xtype: 'button', text: 'Update', reference: 'updateBtn', handler: 'updateParams', bind: { disabled: '{livemode}' } } ] }, items: [ { xtype: 'box', reference: 'content', style: { font: 'normal 11px tahoma, arial, verdana, sans-serif', 'white-space': 'pre' }, } ] });