diff --git a/panel/LogView.js b/panel/LogView.js
index 05a90a3..fe8d274 100644
--- a/panel/LogView.js
+++ b/panel/LogView.js
@@ -5,270 +5,256 @@
*/
Ext.define('Proxmox.panel.LogView', {
extend: 'Ext.panel.Panel',
-
- alias: ['widget.proxmoxLogView'],
+ xtype: 'proxmoxLogView',
pageSize: 500,
-
+ viewBuffer: 50,
lineHeight: 16,
- viewInfo: undefined,
-
scrollToEnd: true,
- autoScroll: true,
+ // callback for load failure, used for ceph
+ failCallback: undefined,
- layout: 'auto',
+ controller: {
+ xclass: 'Ext.app.ViewController',
- bodyPadding: 5,
-
- getMaxDown: function(scrollToEnd) {
- var me = this;
-
- var target = me.getTargetEl();
- var dom = target.dom;
- if (scrollToEnd) {
- dom.scrollTop = dom.scrollHeight - dom.clientHeight;
- }
-
- var maxDown = dom.scrollHeight - dom.clientHeight -
- dom.scrollTop;
-
- return maxDown;
- },
-
- updateView: function(start, end, total, text) {
- var me = this;
-
- if (me.destroyed) { // return if element is not there anymore
- return;
- }
-
- var el = me.dataCmp.el;
-
- if (me.viewInfo && me.viewInfo.start === start &&
- me.viewInfo.end === end && me.viewInfo.total === total &&
- me.viewInfo.textLength === text.length) {
- return; // same content
- }
-
- var maxDown = me.getMaxDown();
- var scrollToEnd = (maxDown <= 0) && me.scrollToEnd;
-
- el.setStyle('padding-top', (start*me.lineHeight).toString() + 'px');
- el.update(text);
- me.dataCmp.setHeight(total*me.lineHeight);
-
- if (scrollToEnd) {
- me.getMaxDown(true);
- }
-
- me.viewInfo = {
- start: start,
- end: end,
- total: total,
- textLength: text.length
- };
- },
-
- doAttemptLoad: function(start) {
- var me = this;
-
- var req_params = {
- start: start,
- limit: me.pageSize
- };
-
- if (me.log_select_timespan) {
- // always show log until the end of the selected day
- req_params.until = Ext.Date.format(me.until_date, 'Y-m-d') + ' 23:59:59';
- req_params.since = Ext.Date.format(me.since_date, 'Y-m-d');
- }
-
- Proxmox.Utils.API2Request({
- url: me.url,
- params: req_params,
- method: 'GET',
- success: function(response) {
- Proxmox.Utils.setErrorMask(me, false);
- var list = response.result.data;
- var total = response.result.total;
- var first = 0, last = 0;
- var text = '';
- Ext.Array.each(list, function(item) {
- if (!first|| item.n < first) {
- first = item.n;
- }
- if (!last || item.n > last) {
- last = item.n;
- }
- text = text + Ext.htmlEncode(item.t) + "
";
- });
-
- if (first && last && total) {
- me.updateView(first -1 , last -1, total, text);
- } else {
- me.updateView(0, 0, 0, '');
- }
- },
- failure: function(response) {
- var msg = response.htmlStatus;
- Proxmox.Utils.setErrorMask(me, msg);
- }
- });
- },
-
- attemptLoad: function(start) {
- var me = this;
- if (!me.loadTask) {
- me.loadTask = Ext.create('Ext.util.DelayedTask', me.doAttemptLoad, me, []);
- }
- me.loadTask.delay(200, me.doAttemptLoad, me, [start]);
- },
-
- requestUpdate: function(top, force) {
- var me = this;
-
- if (top === undefined) {
- var target = me.getTargetEl();
- top = target.dom.scrollTop;
- }
-
- var viewStart = parseInt((top / me.lineHeight) - 1, 10);
- if (viewStart < 0) {
- viewStart = 0;
- }
- var viewEnd = parseInt(((top + me.getHeight())/ me.lineHeight) + 1, 10);
- var info = me.viewInfo;
-
- if (info && !force) {
- if (viewStart >= info.start && viewEnd <= info.end) {
+ updateParams: function() {
+ var me = this;
+ var viewModel = me.getViewModel();
+ var since = viewModel.get('since');
+ var until = viewModel.get('until');
+ if (viewModel.get('hide_timespan')) {
return;
}
- }
- var line = parseInt((top / me.lineHeight) - (me.pageSize / 2) + 10, 10);
- if (line < 0) {
- line = 0;
- }
-
- me.attemptLoad(line);
- },
-
- afterRender: function() {
- var me = this;
-
- me.callParent(arguments);
-
- Ext.Function.defer(function() {
- var target = me.getTargetEl();
- target.on('scroll', function(e) {
- me.requestUpdate();
- });
- me.requestUpdate(0);
- }, 20);
- },
-
- initComponent : function() {
- /*jslint confusion: true */
-
- var me = this;
-
- if (!me.url) {
- throw "no url specified";
- }
-
- // show logs from today back to 3 days ago per default
- me.until_date = new Date();
- me.since_date = new Date();
- me.since_date.setDate(me.until_date.getDate() - 3);
-
- me.dataCmp = Ext.create('Ext.Component', {
- style: 'font:normal 11px tahoma, arial, verdana, sans-serif;' +
- 'line-height: ' + me.lineHeight.toString() + 'px; white-space: pre;'
- });
-
- me.task = Ext.TaskManager.start({
- run: function() {
- if (!me.isVisible() || !me.scrollToEnd || !me.viewInfo) {
- return;
- }
-
- var maxDown = me.getMaxDown();
- if (maxDown > 0) {
- return;
- }
-
- me.requestUpdate(undefined, true);
- },
- interval: 1000
- });
-
- Ext.apply(me, {
- items: me.dataCmp,
- listeners: {
- destroy: function() {
- Ext.TaskManager.stop(me.task);
- }
+ if (since > until) {
+ Ext.Msg.alert('Error', 'Since date must be less equal than Until date.');
+ return;
}
- });
- if (me.log_select_timespan) {
- me.tbar = ['->','Since: ',
- {
- xtype: 'datefield',
- maxValue: me.until_date,
- value: me.since_date,
- name: 'since_date',
- format: 'Y-m-d',
- listeners: {
- select: function(field, date) {
- me.since_date_selected = date;
- var until_field = field.up().down('field[name=until_date]');
- if (date > until_field.getValue()) {
- until_field.setValue(date);
- }
- }
- }
- },
- 'Until: ',
- {
- xtype: 'datefield',
- maxValue: me.until_date,
- value: me.until_date,
- name: 'until_date',
- format: 'Y-m-d',
- listeners: {
- select: function(field, date) {
- var since_field = field.up().down('field[name=since_date]');
- if (date < since_field.getValue()) {
- since_field.setValue(date);
- }
- }
- }
- },
- {
- xtype: 'button',
- text: 'Update',
- handler: function() {
- var until_field = me.down('field[name=until_date]');
- var since_field = me.down('field[name=since_date]');
- if (until_field.getValue() < since_field.getValue()) {
- Ext.Msg.alert('Error',
- 'Since date must be less equal than Until date.');
- until_field.setValue(me.until_date);
- since_field.setValue(me.since_date);
- } else {
- me.until_date = until_field.getValue();
- me.since_date = since_field.getValue();
- me.requestUpdate();
- }
- }
- }
- ];
+ viewModel.set('params.since', Ext.Date.format(since, 'Y-m-d'));
+ viewModel.set('params.until', Ext.Date.format(until, 'Y-m-d') + ' 23:59:59');
+ me.getView().loadTask.delay(200);
+ },
+
+ scrollPosBottom: function() {
+ var view = this.getView();
+ var pos = view.getScrollY();
+ var maxPos = view.getScrollable().getMaxPosition().y;
+ return maxPos - pos;
+ },
+
+ updateView: function(text, first, total) {
+ var me = this;
+ var view = me.getView();
+ var viewModel = me.getViewModel();
+ var content = me.lookup('content');
+ var data = viewModel.get('data');
+
+ if (first === data.first && total === data.total && text.length === data.textlen) {
+ return; // same content, skip setting and scrolling
+ }
+ viewModel.set('data', {
+ first: first,
+ total: total,
+ textlen: text.length
+ });
+
+ var scrollPos = me.scrollPosBottom();
+
+ content.update(text);
+
+ if (view.scrollToEnd && scrollPos <= 0) {
+ // we use setTimeout to work around scroll handling on touchscreens
+ setTimeout(function() { view.scrollTo(0, Infinity); }, 10);
+ }
+ },
+
+ doLoad: function() {
+ var me = this;
+ var view = me.getView();
+ var viewModel = me.getViewModel();
+ Proxmox.Utils.API2Request({
+ url: me.getView().url,
+ params: viewModel.get('params'),
+ method: 'GET',
+ success: function(response) {
+ Proxmox.Utils.setErrorMask(me, false);
+ var total = response.result.total;
+ var lines = new Array();
+ var first = Infinity;
+
+ Ext.Array.each(response.result.data, function(line) {
+ if (first > line.n) {
+ first = line.n;
+ }
+ lines[line.n - 1] = Ext.htmlEncode(line.t);
+ });
+
+ lines.length = total;
+ me.updateView(lines.join('
'), first - 1, total);
+ },
+ failure: function(response) {
+ if (view.failCallback) {
+ view.failCallback(response);
+ } else {
+ var msg = response.htmlStatus;
+ Proxmox.Utils.setErrorMask(me, msg);
+ }
+ }
+ });
+ },
+
+ onScroll: function(x, y) {
+ var me = this;
+ var view = me.getView();
+ var viewModel = me.getViewModel();
+
+ var lineHeight = view.lineHeight;
+ var line = view.getScrollY()/lineHeight;
+ var start = viewModel.get('params.start');
+ var limit = viewModel.get('params.limit');
+ var viewLines = view.getHeight()/lineHeight;
+
+ var viewStart = Math.max(parseInt(line - 1 - view.viewBuffer, 10), 0);
+ var viewEnd = parseInt(line + viewLines + 1 + view.viewBuffer, 10);
+
+ if (viewStart < start || viewEnd > (start+limit)) {
+ viewModel.set('params.start',
+ Math.max(parseInt(line - limit/2 + 10, 10), 0));
+ view.loadTask.delay(200);
+ }
+ },
+
+ init: function(view) {
+ var me = this;
+
+ if (!view.url) {
+ throw "no url specified";
+ }
+
+ var viewModel = this.getViewModel();
+ var since = new Date();
+ since.setDate(since.getDate() - 3);
+ viewModel.set('until', new Date());
+ viewModel.set('since', since);
+ viewModel.set('params.limit', view.pageSize);
+ viewModel.set('hide_timespan', !view.log_select_timespan);
+ me.lookup('content').setStyle('line-height', view.lineHeight + 'px');
+
+ view.loadTask = new Ext.util.DelayedTask(me.doLoad, me);
+
+ me.updateParams();
+ view.task = Ext.TaskManager.start({
+ run: function() {
+ if (!view.isVisible() || !view.scrollToEnd) {
+ return;
+ }
+
+ if (me.scrollPosBottom() <= 1) {
+ view.loadTask.delay(200);
+ }
+ },
+ interval: 1000
+ });
}
+ },
+ onDestroy: function() {
+ var me = this;
+ me.loadTask.cancel();
+ Ext.TaskManager.stop(me.task);
+ },
- me.callParent();
- }
+ // for user to initiate a load from outside
+ requestUpdate: function() {
+ var me = this;
+ me.loadTask.delay(200);
+ },
+
+ viewModel: {
+ data: {
+ until: null,
+ since: null,
+ hide_timespan: false,
+ data: {
+ start: 0,
+ total: 0,
+ textlen: 0
+ },
+ params: {
+ start: 0,
+ limit: 500,
+ }
+ }
+ },
+
+ 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: {
+ bind: {
+ hidden: '{hide_timespan}'
+ },
+ items: [
+ '->',
+ 'Since: ',
+ {
+ xtype: 'datefield',
+ name: 'since_date',
+ reference: 'since',
+ format: 'Y-m-d',
+ bind: {
+ value: '{since}',
+ maxValue: '{until}'
+ }
+ },
+ 'Until: ',
+ {
+ xtype: 'datefield',
+ name: 'until_date',
+ reference: 'until',
+ format: 'Y-m-d',
+ bind: {
+ value: '{until}',
+ minValue: '{since}'
+ }
+ },
+ {
+ xtype: 'button',
+ text: 'Update',
+ handler: 'updateParams'
+ }
+ ],
+ },
+
+ items: [
+ {
+ xtype: 'box',
+ reference: 'content',
+ style: {
+ font: 'normal 11px tahoma, arial, verdana, sans-serif',
+ 'white-space': 'pre'
+ },
+ }
+ ]
});
diff --git a/window/TaskViewer.js b/window/TaskViewer.js
index 39f42ad..b508882 100644
--- a/window/TaskViewer.js
+++ b/window/TaskViewer.js
@@ -198,8 +198,8 @@ Ext.define('Proxmox.window.TaskViewer', {
var status = statgrid.getObjectValue('status');
if (status === 'stopped') {
- logView.requestUpdate(undefined, true);
logView.scrollToEnd = false;
+ logView.requestUpdate();
statstore.stopUpdate();
me.taskDone(statgrid.getObjectValue('exitstatus') == 'OK');
}