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