]> git.proxmox.com Git - proxmox-widget-toolkit.git/blame - src/panel/LogView.js
ui: logpanel: catch up to very fast task logs with api calls
[proxmox-widget-toolkit.git] / src / panel / LogView.js
CommitLineData
de2e10b5
DM
1/*
2 * Display log entries in a panel with scrollbar
3 * The log entries are automatically refreshed via a background task,
4 * with newest entries comming at the bottom
5 */
6Ext.define('Proxmox.panel.LogView', {
7 extend: 'Ext.panel.Panel',
65bb3b67 8 xtype: 'proxmoxLogView',
de2e10b5
DM
9
10 pageSize: 500,
65bb3b67 11 viewBuffer: 50,
de2e10b5
DM
12 lineHeight: 16,
13
de2e10b5
DM
14 scrollToEnd: true,
15
65bb3b67
DC
16 // callback for load failure, used for ceph
17 failCallback: undefined,
de2e10b5 18
65bb3b67
DC
19 controller: {
20 xclass: 'Ext.app.ViewController',
de2e10b5 21
65bb3b67 22 updateParams: function() {
05a977a2
TL
23 let me = this;
24 let viewModel = me.getViewModel();
25 let since = viewModel.get('since');
26 let until = viewModel.get('until');
65bb3b67
DC
27 if (viewModel.get('hide_timespan')) {
28 return;
29 }
de2e10b5 30
65bb3b67
DC
31 if (since > until) {
32 Ext.Msg.alert('Error', 'Since date must be less equal than Until date.');
33 return;
34 }
de2e10b5 35
65bb3b67
DC
36 viewModel.set('params.since', Ext.Date.format(since, 'Y-m-d'));
37 viewModel.set('params.until', Ext.Date.format(until, 'Y-m-d') + ' 23:59:59');
38 me.getView().loadTask.delay(200);
39 },
40
41 scrollPosBottom: function() {
05a977a2
TL
42 let view = this.getView();
43 let pos = view.getScrollY();
44 let maxPos = view.getScrollable().getMaxPosition().y;
65bb3b67
DC
45 return maxPos - pos;
46 },
47
b5ff20a6 48 updateView: function(lines, first, total) {
05a977a2
TL
49 let me = this;
50 let view = me.getView();
51 let viewModel = me.getViewModel();
52 let content = me.lookup('content');
53 let data = viewModel.get('data');
65bb3b67 54
b5ff20a6 55 if (first === data.first && total === data.total && lines.length === data.lines) {
65bb3b67
DC
56 return; // same content, skip setting and scrolling
57 }
58 viewModel.set('data', {
59 first: first,
60 total: total,
b5ff20a6 61 lines: lines.length,
65bb3b67 62 });
de2e10b5 63
05a977a2 64 let scrollPos = me.scrollPosBottom();
b5ff20a6 65 let scrollToBottom = view.scrollToEnd && scrollPos <= 5;
de2e10b5 66
b5ff20a6
DC
67 if (!scrollToBottom) {
68 // so that we have the 'correct' height for the text
69 lines.length = total;
70 }
71
72 content.update(lines.join('<br>'));
de2e10b5 73
b5ff20a6 74 if (scrollToBottom) {
2f474118
DC
75 let scroller = view.getScrollable();
76 scroller.suspendEvent('scroll');
77 view.scrollTo(0, Infinity);
78 me.updateStart(true);
79 scroller.resumeEvent('scroll');
65bb3b67
DC
80 }
81 },
82
83 doLoad: function() {
05a977a2 84 let me = this;
72be386c
TL
85 if (me.running) {
86 me.requested = true;
87 return;
88 }
7f9a6567 89 me.running = true;
05a977a2
TL
90 let view = me.getView();
91 let viewModel = me.getViewModel();
65bb3b67
DC
92 Proxmox.Utils.API2Request({
93 url: me.getView().url,
94 params: viewModel.get('params'),
95 method: 'GET',
96 success: function(response) {
97 Proxmox.Utils.setErrorMask(me, false);
05a977a2
TL
98 let total = response.result.total;
99 let lines = [];
100 let first = Infinity;
65bb3b67
DC
101
102 Ext.Array.each(response.result.data, function(line) {
103 if (first > line.n) {
104 first = line.n;
105 }
106 lines[line.n - 1] = Ext.htmlEncode(line.t);
107 });
108
b5ff20a6 109 me.updateView(lines, first - 1, total);
7f9a6567 110 me.running = false;
72be386c
TL
111 if (me.requested) {
112 me.requested = false;
113 view.loadTask.delay(200);
114 }
65bb3b67
DC
115 },
116 failure: function(response) {
117 if (view.failCallback) {
118 view.failCallback(response);
119 } else {
05a977a2 120 let msg = response.htmlStatus;
65bb3b67 121 Proxmox.Utils.setErrorMask(me, msg);
de2e10b5 122 }
7f9a6567 123 me.running = false;
72be386c
TL
124 if (me.requested) {
125 me.requested = false;
126 view.loadTask.delay(200);
127 }
01031528 128 },
65bb3b67
DC
129 });
130 },
131
2f474118
DC
132 updateStart: function(scrolledToBottom, targetLine) {
133 let me = this;
134 let view = me.getView();
135 let viewModel = me.getViewModel();
136
137 let limit = viewModel.get('params.limit');
138
139 if (scrolledToBottom) {
140 let total = viewModel.get('data.total');
141 viewModel.set('params.start',
142 Math.max(parseInt(total - limit, 10), 0));
143 } else {
144 viewModel.set('params.start',
145 Math.max(parseInt(targetLine - (limit / 2) + 10, 10), 0));
146 }
147
148 view.loadTask.delay(200);
149 },
150
65bb3b67 151 onScroll: function(x, y) {
05a977a2
TL
152 let me = this;
153 let view = me.getView();
154 let viewModel = me.getViewModel();
65bb3b67 155
05a977a2
TL
156 let lineHeight = view.lineHeight;
157 let line = view.getScrollY()/lineHeight;
158 let start = viewModel.get('params.start');
159 let limit = viewModel.get('params.limit');
160 let viewLines = view.getHeight()/lineHeight;
65bb3b67 161
05a977a2
TL
162 let viewStart = Math.max(parseInt(line - 1 - view.viewBuffer, 10), 0);
163 let viewEnd = parseInt(line + viewLines + 1 + view.viewBuffer, 10);
65bb3b67 164
01031528 165 if (viewStart < start || viewEnd > start+limit) {
2f474118 166 me.updateStart(false, line);
de2e10b5 167 }
65bb3b67 168 },
de2e10b5 169
65bb3b67 170 init: function(view) {
05a977a2 171 let me = this;
de2e10b5 172
65bb3b67
DC
173 if (!view.url) {
174 throw "no url specified";
de2e10b5 175 }
de2e10b5 176
05a977a2
TL
177 let viewModel = this.getViewModel();
178 let since = new Date();
65bb3b67
DC
179 since.setDate(since.getDate() - 3);
180 viewModel.set('until', new Date());
181 viewModel.set('since', since);
182 viewModel.set('params.limit', view.pageSize);
183 viewModel.set('hide_timespan', !view.log_select_timespan);
184 me.lookup('content').setStyle('line-height', view.lineHeight + 'px');
185
186 view.loadTask = new Ext.util.DelayedTask(me.doLoad, me);
187
188 me.updateParams();
189 view.task = Ext.TaskManager.start({
190 run: function() {
191 if (!view.isVisible() || !view.scrollToEnd) {
192 return;
193 }
de2e10b5 194
aa9607f1 195 if (me.scrollPosBottom() <= 5) {
72be386c 196 view.loadTask.delay(200);
65bb3b67
DC
197 }
198 },
01031528 199 interval: 1000,
65bb3b67 200 });
01031528 201 },
de2e10b5
DM
202 },
203
65bb3b67 204 onDestroy: function() {
05a977a2 205 let me = this;
65bb3b67
DC
206 me.loadTask.cancel();
207 Ext.TaskManager.stop(me.task);
de2e10b5
DM
208 },
209
65bb3b67
DC
210 // for user to initiate a load from outside
211 requestUpdate: function() {
05a977a2 212 let me = this;
65bb3b67
DC
213 me.loadTask.delay(200);
214 },
de2e10b5 215
65bb3b67
DC
216 viewModel: {
217 data: {
218 until: null,
219 since: null,
220 hide_timespan: false,
221 data: {
222 start: 0,
223 total: 0,
01031528 224 textlen: 0,
65bb3b67
DC
225 },
226 params: {
227 start: 0,
228 limit: 500,
01031528
TL
229 },
230 },
65bb3b67 231 },
de2e10b5 232
65bb3b67
DC
233 layout: 'auto',
234 bodyPadding: 5,
235 scrollable: {
236 x: 'auto',
237 y: 'auto',
238 listeners: {
239 // we have to have this here, since we cannot listen to events
240 // of the scroller in the viewcontroller (extjs bug?), nor does
241 // the panel have a 'scroll' event'
242 scroll: {
243 fn: function(scroller, x, y) {
05a977a2 244 let controller = this.component.getController();
65bb3b67 245 if (controller) { // on destroy, controller can be gone
01031528 246 controller.onScroll(x, y);
65bb3b67
DC
247 }
248 },
01031528 249 buffer: 200,
65bb3b67 250 },
01031528 251 },
65bb3b67 252 },
de2e10b5 253
65bb3b67
DC
254 tbar: {
255 bind: {
01031528 256 hidden: '{hide_timespan}',
65bb3b67
DC
257 },
258 items: [
259 '->',
260 'Since: ',
261 {
262 xtype: 'datefield',
263 name: 'since_date',
264 reference: 'since',
265 format: 'Y-m-d',
266 bind: {
267 value: '{since}',
01031528
TL
268 maxValue: '{until}',
269 },
de2e10b5 270 },
65bb3b67
DC
271 'Until: ',
272 {
273 xtype: 'datefield',
274 name: 'until_date',
275 reference: 'until',
276 format: 'Y-m-d',
277 bind: {
278 value: '{until}',
01031528
TL
279 minValue: '{since}',
280 },
65bb3b67
DC
281 },
282 {
283 xtype: 'button',
284 text: 'Update',
01031528
TL
285 handler: 'updateParams',
286 },
65bb3b67
DC
287 ],
288 },
de2e10b5 289
65bb3b67
DC
290 items: [
291 {
292 xtype: 'box',
293 reference: 'content',
294 style: {
295 font: 'normal 11px tahoma, arial, verdana, sans-serif',
01031528 296 'white-space': 'pre',
65bb3b67 297 },
01031528
TL
298 },
299 ],
de2e10b5 300});