add panel/JournalView

similar to LogView, but expects the result from the /node/journal api call,
which is an array of strings, with start/endcursor instead of
an array of objects with line numbers

the new api call also does not accept start line numbers and limit,
so it is necessary to handle it differently

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
This commit is contained in:
Dominik Csapak 2019-05-15 11:15:12 +02:00 committed by Thomas Lamprecht
parent 8e2d096c7f
commit a1498508da
2 changed files with 336 additions and 0 deletions

View File

@ -40,6 +40,7 @@ JSSRC= \
grid/PendingObjectGrid.js \
panel/InputPanel.js \
panel/LogView.js \
panel/JournalView.js \
panel/RRDChart.js \
panel/GaugeWidget.js \
window/Edit.js \

335
panel/JournalView.js Normal file
View File

@ -0,0 +1,335 @@
/*
* 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('<br>');
if (!livemode) {
view.content = num ? text : 'no content';
} else {
// update content
if (top && num) {
view.content = view.content ? text + '<br>' + view.content : text;
} else if (!top && num) {
view.content = view.content ? view.content + '<br>' + 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: 'datefield',
fieldLabel: gettext('Since'),
name: 'since_date',
reference: 'since',
format: 'Y-m-d',
bind: {
disabled: '{livemode}',
value: '{since}',
maxValue: '{until}'
}
},
{
xtype: 'datefield',
fieldLabel: gettext('Until'),
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'
},
}
]
});