]> git.proxmox.com Git - proxmox-widget-toolkit.git/blob - panel/JournalView.js
use eslint and execute as check target
[proxmox-widget-toolkit.git] / panel / JournalView.js
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 */
6 Ext.define('Proxmox.panel.JournalView', {
7 extend: 'Ext.panel.Panel',
8 xtype: 'proxmoxJournalView',
9
10 numEntries: 500,
11 lineHeight: 16,
12
13 scrollToEnd: true,
14
15 controller: {
16 xclass: 'Ext.app.ViewController',
17
18 updateParams: function() {
19 let me = this;
20 let viewModel = me.getViewModel();
21 let since = viewModel.get('since');
22 let until = viewModel.get('until');
23
24 since.setHours(0, 0, 0, 0);
25 until.setHours(0, 0, 0, 0);
26 until.setDate(until.getDate()+1);
27
28 me.getView().loadTask.delay(200, undefined, undefined, [
29 false,
30 false,
31 Ext.Date.format(since, "U"),
32 Ext.Date.format(until, "U"),
33 ]);
34 },
35
36 scrollPosBottom: function() {
37 let view = this.getView();
38 let pos = view.getScrollY();
39 let maxPos = view.getScrollable().getMaxPosition().y;
40 return maxPos - pos;
41 },
42
43 scrollPosTop: function() {
44 let view = this.getView();
45 return view.getScrollY();
46 },
47
48 updateScroll: function(livemode, num, scrollPos, scrollPosTop) {
49 let me = this;
50 let view = me.getView();
51
52 if (!livemode) {
53 setTimeout(function() { view.scrollTo(0, 0); }, 10);
54 } else if (view.scrollToEnd && scrollPos <= 0) {
55 setTimeout(function() { view.scrollTo(0, Infinity); }, 10);
56 } else if (!view.scrollToEnd && scrollPosTop < 20 * view.lineHeight) {
57 setTimeout(function() { view.scrollTo(0, (num * view.lineHeight) + scrollPosTop); }, 10);
58 }
59 },
60
61 updateView: function(lines, livemode, top) {
62 let me = this;
63 let view = me.getView();
64 let viewmodel = me.getViewModel();
65 if (!viewmodel || viewmodel.get('livemode') !== livemode) {
66 return; // we switched mode, do not update the content
67 }
68 let contentEl = me.lookup('content');
69
70 // save old scrollpositions
71 let scrollPos = me.scrollPosBottom();
72 let scrollPosTop = me.scrollPosTop();
73
74 let newend = lines.shift();
75 let newstart = lines.pop();
76
77 let num = lines.length;
78 let text = lines.map(Ext.htmlEncode).join('<br>');
79
80 if (!livemode) {
81 if (num) {
82 view.content = text;
83 } else {
84 view.content = 'nothing logged or no timespan selected';
85 }
86 } else {
87 // update content
88 if (top && num) {
89 view.content = view.content ? text + '<br>' + view.content : text;
90 } else if (!top && num) {
91 view.content = view.content ? view.content + '<br>' + text : text;
92 }
93
94 // update cursors
95 if (!top || !view.startcursor) {
96 view.startcursor = newstart;
97 }
98
99 if (top || !view.endcursor) {
100 view.endcursor = newend;
101 }
102 }
103
104 contentEl.update(view.content);
105
106 me.updateScroll(livemode, num, scrollPos, scrollPosTop);
107 },
108
109 doLoad: function(livemode, top, since, until) {
110 let me = this;
111 if (me.running) {
112 me.requested = true;
113 return;
114 }
115 me.running = true;
116 let view = me.getView();
117 let params = {
118 lastentries: view.numEntries || 500,
119 };
120 if (livemode) {
121 if (!top && view.startcursor) {
122 params = {
123 startcursor: view.startcursor,
124 };
125 } else if (view.endcursor) {
126 params.endcursor = view.endcursor;
127 }
128 } else {
129 params = {
130 since: since,
131 until: until,
132 };
133 }
134 Proxmox.Utils.API2Request({
135 url: view.url,
136 params: params,
137 waitMsgTarget: !livemode ? view : undefined,
138 method: 'GET',
139 success: function(response) {
140 Proxmox.Utils.setErrorMask(me, false);
141 let lines = response.result.data;
142 me.updateView(lines, livemode, top);
143 me.running = false;
144 if (me.requested) {
145 me.requested = false;
146 view.loadTask.delay(200);
147 }
148 },
149 failure: function(response) {
150 let msg = response.htmlStatus;
151 Proxmox.Utils.setErrorMask(me, msg);
152 me.running = false;
153 if (me.requested) {
154 me.requested = false;
155 view.loadTask.delay(200);
156 }
157 },
158 });
159 },
160
161 onScroll: function(x, y) {
162 let me = this;
163 let view = me.getView();
164 let viewmodel = me.getViewModel();
165 let livemode = viewmodel.get('livemode');
166 if (!livemode) {
167 return;
168 }
169
170 if (me.scrollPosTop() < 20*view.lineHeight) {
171 view.scrollToEnd = false;
172 view.loadTask.delay(200, undefined, undefined, [true, true]);
173 } else if (me.scrollPosBottom() <= 1) {
174 view.scrollToEnd = true;
175 }
176 },
177
178 init: function(view) {
179 let me = this;
180
181 if (!view.url) {
182 throw "no url specified";
183 }
184
185 let viewmodel = me.getViewModel();
186 let viewModel = this.getViewModel();
187 let since = new Date();
188 since.setDate(since.getDate() - 3);
189 viewModel.set('until', new Date());
190 viewModel.set('since', since);
191 me.lookup('content').setStyle('line-height', view.lineHeight + 'px');
192
193 view.loadTask = new Ext.util.DelayedTask(me.doLoad, me, [true, false]);
194
195 me.updateParams();
196 view.task = Ext.TaskManager.start({
197 run: function() {
198 if (!view.isVisible() || !view.scrollToEnd || !viewmodel.get('livemode')) {
199 return;
200 }
201
202 if (me.scrollPosBottom() <= 1) {
203 view.loadTask.delay(200, undefined, undefined, [true, false]);
204 }
205 },
206 interval: 1000,
207 });
208 },
209
210 onLiveMode: function() {
211 let me = this;
212 let view = me.getView();
213 delete view.startcursor;
214 delete view.endcursor;
215 delete view.content;
216 me.getViewModel().set('livemode', true);
217 view.scrollToEnd = true;
218 me.updateView([], true, false);
219 },
220
221 onTimespan: function() {
222 let me = this;
223 me.getViewModel().set('livemode', false);
224 me.updateView([], false);
225 },
226 },
227
228 onDestroy: function() {
229 let me = this;
230 me.loadTask.cancel();
231 Ext.TaskManager.stop(me.task);
232 delete me.content;
233 },
234
235 // for user to initiate a load from outside
236 requestUpdate: function() {
237 let me = this;
238 me.loadTask.delay(200);
239 },
240
241 viewModel: {
242 data: {
243 livemode: true,
244 until: null,
245 since: null,
246 },
247 },
248
249 layout: 'auto',
250 bodyPadding: 5,
251 scrollable: {
252 x: 'auto',
253 y: 'auto',
254 listeners: {
255 // we have to have this here, since we cannot listen to events
256 // of the scroller in the viewcontroller (extjs bug?), nor does
257 // the panel have a 'scroll' event'
258 scroll: {
259 fn: function(scroller, x, y) {
260 let controller = this.component.getController();
261 if (controller) { // on destroy, controller can be gone
262 controller.onScroll(x, y);
263 }
264 },
265 buffer: 200,
266 },
267 },
268 },
269
270 tbar: {
271
272 items: [
273 '->',
274 {
275 xtype: 'segmentedbutton',
276 items: [
277 {
278 text: gettext('Live Mode'),
279 bind: {
280 pressed: '{livemode}',
281 },
282 handler: 'onLiveMode',
283 },
284 {
285 text: gettext('Select Timespan'),
286 bind: {
287 pressed: '{!livemode}',
288 },
289 handler: 'onTimespan',
290 },
291 ],
292 },
293 {
294 xtype: 'box',
295 bind: { disabled: '{livemode}' },
296 autoEl: { cn: gettext('Since') + ':' },
297 },
298 {
299 xtype: 'datefield',
300 name: 'since_date',
301 reference: 'since',
302 format: 'Y-m-d',
303 bind: {
304 disabled: '{livemode}',
305 value: '{since}',
306 maxValue: '{until}',
307 },
308 },
309 {
310 xtype: 'box',
311 bind: { disabled: '{livemode}' },
312 autoEl: { cn: gettext('Until') + ':' },
313 },
314 {
315 xtype: 'datefield',
316 name: 'until_date',
317 reference: 'until',
318 format: 'Y-m-d',
319 bind: {
320 disabled: '{livemode}',
321 value: '{until}',
322 minValue: '{since}',
323 },
324 },
325 {
326 xtype: 'button',
327 text: 'Update',
328 reference: 'updateBtn',
329 handler: 'updateParams',
330 bind: {
331 disabled: '{livemode}',
332 },
333 },
334 ],
335 },
336
337 items: [
338 {
339 xtype: 'box',
340 reference: 'content',
341 style: {
342 font: 'normal 11px tahoma, arial, verdana, sans-serif',
343 'white-space': 'pre',
344 },
345 },
346 ],
347 });