]>
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); | |
54 | } else if (view.scrollToEnd && scrollPos <= 0) { | |
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 DC |
79 | |
80 | if (!livemode) { | |
70df8f46 TL |
81 | if (num) { |
82 | view.content = text; | |
83 | } else { | |
84 | view.content = 'nothing logged or no timespan selected'; | |
85 | } | |
a1498508 DC |
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) { | |
05a977a2 | 110 | let me = this; |
a1498508 DC |
111 | if (me.running) { |
112 | me.requested = true; | |
113 | return; | |
114 | } | |
115 | me.running = true; | |
05a977a2 TL |
116 | let view = me.getView(); |
117 | let params = { | |
a1498508 DC |
118 | lastentries: view.numEntries || 500, |
119 | }; | |
120 | if (livemode) { | |
121 | if (!top && view.startcursor) { | |
122 | params = { | |
01031528 | 123 | startcursor: view.startcursor, |
a1498508 DC |
124 | }; |
125 | } else if (view.endcursor) { | |
126 | params.endcursor = view.endcursor; | |
127 | } | |
128 | } else { | |
129 | params = { | |
130 | since: since, | |
01031528 | 131 | until: until, |
a1498508 DC |
132 | }; |
133 | } | |
134 | Proxmox.Utils.API2Request({ | |
135 | url: view.url, | |
136 | params: params, | |
01031528 | 137 | waitMsgTarget: !livemode ? view : undefined, |
a1498508 DC |
138 | method: 'GET', |
139 | success: function(response) { | |
140 | Proxmox.Utils.setErrorMask(me, false); | |
05a977a2 | 141 | let lines = response.result.data; |
a1498508 DC |
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) { | |
05a977a2 | 150 | let msg = response.htmlStatus; |
a1498508 DC |
151 | Proxmox.Utils.setErrorMask(me, msg); |
152 | me.running = false; | |
153 | if (me.requested) { | |
154 | me.requested = false; | |
155 | view.loadTask.delay(200); | |
156 | } | |
01031528 | 157 | }, |
a1498508 DC |
158 | }); |
159 | }, | |
160 | ||
161 | onScroll: function(x, y) { | |
05a977a2 TL |
162 | let me = this; |
163 | let view = me.getView(); | |
164 | let viewmodel = me.getViewModel(); | |
165 | let livemode = viewmodel.get('livemode'); | |
a1498508 DC |
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) { | |
05a977a2 | 179 | let me = this; |
a1498508 DC |
180 | |
181 | if (!view.url) { | |
182 | throw "no url specified"; | |
183 | } | |
184 | ||
05a977a2 TL |
185 | let viewmodel = me.getViewModel(); |
186 | let viewModel = this.getViewModel(); | |
187 | let since = new Date(); | |
a1498508 DC |
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 | }, | |
01031528 | 206 | interval: 1000, |
a1498508 DC |
207 | }); |
208 | }, | |
209 | ||
210 | onLiveMode: function() { | |
05a977a2 TL |
211 | let me = this; |
212 | let view = me.getView(); | |
a1498508 DC |
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() { | |
05a977a2 | 222 | let me = this; |
a1498508 DC |
223 | me.getViewModel().set('livemode', false); |
224 | me.updateView([], false); | |
01031528 | 225 | }, |
a1498508 DC |
226 | }, |
227 | ||
228 | onDestroy: function() { | |
05a977a2 | 229 | let me = this; |
a1498508 DC |
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() { | |
05a977a2 | 237 | let me = this; |
a1498508 DC |
238 | me.loadTask.delay(200); |
239 | }, | |
240 | ||
241 | viewModel: { | |
242 | data: { | |
243 | livemode: true, | |
244 | until: null, | |
01031528 TL |
245 | since: null, |
246 | }, | |
a1498508 DC |
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) { | |
05a977a2 | 260 | let controller = this.component.getController(); |
a1498508 | 261 | if (controller) { // on destroy, controller can be gone |
01031528 | 262 | controller.onScroll(x, y); |
a1498508 DC |
263 | } |
264 | }, | |
01031528 | 265 | buffer: 200, |
a1498508 | 266 | }, |
01031528 | 267 | }, |
a1498508 DC |
268 | }, |
269 | ||
270 | tbar: { | |
271 | ||
272 | items: [ | |
273 | '->', | |
274 | { | |
275 | xtype: 'segmentedbutton', | |
276 | items: [ | |
277 | { | |
278 | text: gettext('Live Mode'), | |
279 | bind: { | |
01031528 | 280 | pressed: '{livemode}', |
a1498508 DC |
281 | }, |
282 | handler: 'onLiveMode', | |
283 | }, | |
284 | { | |
285 | text: gettext('Select Timespan'), | |
286 | bind: { | |
01031528 | 287 | pressed: '{!livemode}', |
a1498508 DC |
288 | }, |
289 | handler: 'onTimespan', | |
01031528 TL |
290 | }, |
291 | ], | |
a1498508 | 292 | }, |
cd82be49 TL |
293 | { |
294 | xtype: 'box', | |
295 | bind: { disabled: '{livemode}' }, | |
01031528 | 296 | autoEl: { cn: gettext('Since') + ':' }, |
cd82be49 | 297 | }, |
a1498508 DC |
298 | { |
299 | xtype: 'datefield', | |
a1498508 DC |
300 | name: 'since_date', |
301 | reference: 'since', | |
302 | format: 'Y-m-d', | |
303 | bind: { | |
304 | disabled: '{livemode}', | |
305 | value: '{since}', | |
01031528 TL |
306 | maxValue: '{until}', |
307 | }, | |
a1498508 | 308 | }, |
cd82be49 TL |
309 | { |
310 | xtype: 'box', | |
311 | bind: { disabled: '{livemode}' }, | |
01031528 | 312 | autoEl: { cn: gettext('Until') + ':' }, |
cd82be49 | 313 | }, |
a1498508 DC |
314 | { |
315 | xtype: 'datefield', | |
a1498508 DC |
316 | name: 'until_date', |
317 | reference: 'until', | |
318 | format: 'Y-m-d', | |
319 | bind: { | |
320 | disabled: '{livemode}', | |
321 | value: '{until}', | |
01031528 TL |
322 | minValue: '{since}', |
323 | }, | |
a1498508 DC |
324 | }, |
325 | { | |
326 | xtype: 'button', | |
327 | text: 'Update', | |
328 | reference: 'updateBtn', | |
329 | handler: 'updateParams', | |
330 | bind: { | |
01031528 TL |
331 | disabled: '{livemode}', |
332 | }, | |
333 | }, | |
334 | ], | |
a1498508 DC |
335 | }, |
336 | ||
337 | items: [ | |
338 | { | |
339 | xtype: 'box', | |
340 | reference: 'content', | |
341 | style: { | |
342 | font: 'normal 11px tahoma, arial, verdana, sans-serif', | |
01031528 | 343 | 'white-space': 'pre', |
a1498508 | 344 | }, |
01031528 TL |
345 | }, |
346 | ], | |
a1498508 | 347 | }); |