]>
Commit | Line | Data |
---|---|---|
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 | */ | |
6 | Ext.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 | }); |