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