]> git.proxmox.com Git - proxmox-widget-toolkit.git/blob - panel/LogView.js
rework panel/LogView
[proxmox-widget-toolkit.git] / panel / LogView.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.LogView', {
7 extend: 'Ext.panel.Panel',
8 xtype: 'proxmoxLogView',
9
10 pageSize: 500,
11 viewBuffer: 50,
12 lineHeight: 16,
13
14 scrollToEnd: true,
15
16 // callback for load failure, used for ceph
17 failCallback: undefined,
18
19 controller: {
20 xclass: 'Ext.app.ViewController',
21
22 updateParams: function() {
23 var me = this;
24 var viewModel = me.getViewModel();
25 var since = viewModel.get('since');
26 var until = viewModel.get('until');
27 if (viewModel.get('hide_timespan')) {
28 return;
29 }
30
31 if (since > until) {
32 Ext.Msg.alert('Error', 'Since date must be less equal than Until date.');
33 return;
34 }
35
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() {
42 var view = this.getView();
43 var pos = view.getScrollY();
44 var maxPos = view.getScrollable().getMaxPosition().y;
45 return maxPos - pos;
46 },
47
48 updateView: function(text, first, total) {
49 var me = this;
50 var view = me.getView();
51 var viewModel = me.getViewModel();
52 var content = me.lookup('content');
53 var data = viewModel.get('data');
54
55 if (first === data.first && total === data.total && text.length === data.textlen) {
56 return; // same content, skip setting and scrolling
57 }
58 viewModel.set('data', {
59 first: first,
60 total: total,
61 textlen: text.length
62 });
63
64 var scrollPos = me.scrollPosBottom();
65
66 content.update(text);
67
68 if (view.scrollToEnd && scrollPos <= 0) {
69 // we use setTimeout to work around scroll handling on touchscreens
70 setTimeout(function() { view.scrollTo(0, Infinity); }, 10);
71 }
72 },
73
74 doLoad: function() {
75 var me = this;
76 var view = me.getView();
77 var viewModel = me.getViewModel();
78 Proxmox.Utils.API2Request({
79 url: me.getView().url,
80 params: viewModel.get('params'),
81 method: 'GET',
82 success: function(response) {
83 Proxmox.Utils.setErrorMask(me, false);
84 var total = response.result.total;
85 var lines = new Array();
86 var first = Infinity;
87
88 Ext.Array.each(response.result.data, function(line) {
89 if (first > line.n) {
90 first = line.n;
91 }
92 lines[line.n - 1] = Ext.htmlEncode(line.t);
93 });
94
95 lines.length = total;
96 me.updateView(lines.join('<br>'), first - 1, total);
97 },
98 failure: function(response) {
99 if (view.failCallback) {
100 view.failCallback(response);
101 } else {
102 var msg = response.htmlStatus;
103 Proxmox.Utils.setErrorMask(me, msg);
104 }
105 }
106 });
107 },
108
109 onScroll: function(x, y) {
110 var me = this;
111 var view = me.getView();
112 var viewModel = me.getViewModel();
113
114 var lineHeight = view.lineHeight;
115 var line = view.getScrollY()/lineHeight;
116 var start = viewModel.get('params.start');
117 var limit = viewModel.get('params.limit');
118 var viewLines = view.getHeight()/lineHeight;
119
120 var viewStart = Math.max(parseInt(line - 1 - view.viewBuffer, 10), 0);
121 var viewEnd = parseInt(line + viewLines + 1 + view.viewBuffer, 10);
122
123 if (viewStart < start || viewEnd > (start+limit)) {
124 viewModel.set('params.start',
125 Math.max(parseInt(line - limit/2 + 10, 10), 0));
126 view.loadTask.delay(200);
127 }
128 },
129
130 init: function(view) {
131 var me = this;
132
133 if (!view.url) {
134 throw "no url specified";
135 }
136
137 var viewModel = this.getViewModel();
138 var since = new Date();
139 since.setDate(since.getDate() - 3);
140 viewModel.set('until', new Date());
141 viewModel.set('since', since);
142 viewModel.set('params.limit', view.pageSize);
143 viewModel.set('hide_timespan', !view.log_select_timespan);
144 me.lookup('content').setStyle('line-height', view.lineHeight + 'px');
145
146 view.loadTask = new Ext.util.DelayedTask(me.doLoad, me);
147
148 me.updateParams();
149 view.task = Ext.TaskManager.start({
150 run: function() {
151 if (!view.isVisible() || !view.scrollToEnd) {
152 return;
153 }
154
155 if (me.scrollPosBottom() <= 1) {
156 view.loadTask.delay(200);
157 }
158 },
159 interval: 1000
160 });
161 }
162 },
163
164 onDestroy: function() {
165 var me = this;
166 me.loadTask.cancel();
167 Ext.TaskManager.stop(me.task);
168 },
169
170 // for user to initiate a load from outside
171 requestUpdate: function() {
172 var me = this;
173 me.loadTask.delay(200);
174 },
175
176 viewModel: {
177 data: {
178 until: null,
179 since: null,
180 hide_timespan: false,
181 data: {
182 start: 0,
183 total: 0,
184 textlen: 0
185 },
186 params: {
187 start: 0,
188 limit: 500,
189 }
190 }
191 },
192
193 layout: 'auto',
194 bodyPadding: 5,
195 scrollable: {
196 x: 'auto',
197 y: 'auto',
198 listeners: {
199 // we have to have this here, since we cannot listen to events
200 // of the scroller in the viewcontroller (extjs bug?), nor does
201 // the panel have a 'scroll' event'
202 scroll: {
203 fn: function(scroller, x, y) {
204 var controller = this.component.getController();
205 if (controller) { // on destroy, controller can be gone
206 controller.onScroll(x,y);
207 }
208 },
209 buffer: 200
210 },
211 }
212 },
213
214 tbar: {
215 bind: {
216 hidden: '{hide_timespan}'
217 },
218 items: [
219 '->',
220 'Since: ',
221 {
222 xtype: 'datefield',
223 name: 'since_date',
224 reference: 'since',
225 format: 'Y-m-d',
226 bind: {
227 value: '{since}',
228 maxValue: '{until}'
229 }
230 },
231 'Until: ',
232 {
233 xtype: 'datefield',
234 name: 'until_date',
235 reference: 'until',
236 format: 'Y-m-d',
237 bind: {
238 value: '{until}',
239 minValue: '{since}'
240 }
241 },
242 {
243 xtype: 'button',
244 text: 'Update',
245 handler: 'updateParams'
246 }
247 ],
248 },
249
250 items: [
251 {
252 xtype: 'box',
253 reference: 'content',
254 style: {
255 font: 'normal 11px tahoma, arial, verdana, sans-serif',
256 'white-space': 'pre'
257 },
258 }
259 ]
260 });