]> git.proxmox.com Git - proxmox-widget-toolkit.git/blame - src/panel/LogView.js
language selector: increase only picker list view
[proxmox-widget-toolkit.git] / src / panel / LogView.js
CommitLineData
de2e10b5
DM
1/*
2 * Display log entries in a panel with scrollbar
3 * The log entries are automatically refreshed via a background task,
017a6376 4 * with newest entries coming at the bottom
de2e10b5
DM
5 */
6Ext.define('Proxmox.panel.LogView', {
7 extend: 'Ext.panel.Panel',
65bb3b67 8 xtype: 'proxmoxLogView',
de2e10b5 9
4e95d1e9 10 pageSize: 510,
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) {
6971ce9d
TL
56 // before there is any real output, we get 'no output' as a single line, so always
57 // update if we only have one to be sure to catch the first real line of output
80ea69b4
DC
58 if (total !== 1) {
59 return; // same content, skip setting and scrolling
60 }
65bb3b67
DC
61 }
62 viewModel.set('data', {
63 first: first,
64 total: total,
b5ff20a6 65 lines: lines.length,
65bb3b67 66 });
de2e10b5 67
05a977a2 68 let scrollPos = me.scrollPosBottom();
b5ff20a6 69 let scrollToBottom = view.scrollToEnd && scrollPos <= 5;
de2e10b5 70
b5ff20a6
DC
71 if (!scrollToBottom) {
72 // so that we have the 'correct' height for the text
73 lines.length = total;
74 }
75
76 content.update(lines.join('<br>'));
de2e10b5 77
b5ff20a6 78 if (scrollToBottom) {
2f474118
DC
79 let scroller = view.getScrollable();
80 scroller.suspendEvent('scroll');
81 view.scrollTo(0, Infinity);
82 me.updateStart(true);
83 scroller.resumeEvent('scroll');
65bb3b67
DC
84 }
85 },
86
87 doLoad: function() {
05a977a2 88 let me = this;
72be386c
TL
89 if (me.running) {
90 me.requested = true;
91 return;
92 }
7f9a6567 93 me.running = true;
05a977a2
TL
94 let view = me.getView();
95 let viewModel = me.getViewModel();
65bb3b67
DC
96 Proxmox.Utils.API2Request({
97 url: me.getView().url,
98 params: viewModel.get('params'),
99 method: 'GET',
100 success: function(response) {
ed6721d0
DC
101 if (me.isDestroyed) {
102 return;
103 }
65bb3b67 104 Proxmox.Utils.setErrorMask(me, false);
05a977a2
TL
105 let total = response.result.total;
106 let lines = [];
107 let first = Infinity;
65bb3b67
DC
108
109 Ext.Array.each(response.result.data, function(line) {
110 if (first > line.n) {
111 first = line.n;
112 }
113 lines[line.n - 1] = Ext.htmlEncode(line.t);
114 });
115
b5ff20a6 116 me.updateView(lines, first - 1, total);
7f9a6567 117 me.running = false;
72be386c
TL
118 if (me.requested) {
119 me.requested = false;
120 view.loadTask.delay(200);
121 }
65bb3b67
DC
122 },
123 failure: function(response) {
124 if (view.failCallback) {
125 view.failCallback(response);
126 } else {
05a977a2 127 let msg = response.htmlStatus;
65bb3b67 128 Proxmox.Utils.setErrorMask(me, msg);
de2e10b5 129 }
7f9a6567 130 me.running = false;
72be386c
TL
131 if (me.requested) {
132 me.requested = false;
133 view.loadTask.delay(200);
134 }
01031528 135 },
65bb3b67
DC
136 });
137 },
138
2f474118
DC
139 updateStart: function(scrolledToBottom, targetLine) {
140 let me = this;
a16b036b 141 let view = me.getView(), viewModel = me.getViewModel();
2f474118
DC
142
143 let limit = viewModel.get('params.limit');
a16b036b 144 let total = viewModel.get('data.total');
2f474118 145
4e95d1e9
TL
146 // heuristic: scroll up? -> load more in front; scroll down? -> load more at end
147 let startRatio = view.lastTargetLine && view.lastTargetLine > targetLine ? 2/3 : 1/3;
148 view.lastTargetLine = targetLine;
149
a16b036b
TL
150 let newStart = scrolledToBottom
151 ? Math.trunc(total - limit, 10)
4e95d1e9 152 : Math.trunc(targetLine - (startRatio * limit) + 10);
a16b036b
TL
153
154 viewModel.set('params.start', Math.max(newStart, 0));
2f474118
DC
155
156 view.loadTask.delay(200);
157 },
158
65bb3b67 159 onScroll: function(x, y) {
05a977a2 160 let me = this;
a16b036b 161 let view = me.getView(), viewModel = me.getViewModel();
65bb3b67 162
a16b036b
TL
163 let line = view.getScrollY() / view.lineHeight;
164 let viewLines = view.getHeight() / view.lineHeight;
65bb3b67 165
a16b036b
TL
166 let viewStart = Math.max(Math.trunc(line - 1 - view.viewBuffer), 0);
167 let viewEnd = Math.trunc(line + viewLines + 1 + view.viewBuffer);
65bb3b67 168
a16b036b
TL
169 let { start, limit } = viewModel.get('params');
170
1eb5c21d
TL
171 let margin = start < 20 ? 0 : 20;
172
173 if (viewStart < start + margin || viewEnd > start + limit - margin) {
2f474118 174 me.updateStart(false, line);
de2e10b5 175 }
65bb3b67 176 },
de2e10b5 177
65bb3b67 178 init: function(view) {
05a977a2 179 let me = this;
de2e10b5 180
65bb3b67
DC
181 if (!view.url) {
182 throw "no url specified";
de2e10b5 183 }
de2e10b5 184
05a977a2
TL
185 let viewModel = this.getViewModel();
186 let since = new Date();
65bb3b67
DC
187 since.setDate(since.getDate() - 3);
188 viewModel.set('until', new Date());
189 viewModel.set('since', since);
190 viewModel.set('params.limit', view.pageSize);
191 viewModel.set('hide_timespan', !view.log_select_timespan);
a16b036b 192 me.lookup('content').setStyle('line-height', `${view.lineHeight}px`);
65bb3b67
DC
193
194 view.loadTask = new Ext.util.DelayedTask(me.doLoad, me);
195
196 me.updateParams();
197 view.task = Ext.TaskManager.start({
a16b036b 198 run: () => {
65bb3b67
DC
199 if (!view.isVisible() || !view.scrollToEnd) {
200 return;
201 }
aa9607f1 202 if (me.scrollPosBottom() <= 5) {
72be386c 203 view.loadTask.delay(200);
65bb3b67
DC
204 }
205 },
01031528 206 interval: 1000,
65bb3b67 207 });
01031528 208 },
de2e10b5
DM
209 },
210
65bb3b67 211 onDestroy: function() {
05a977a2 212 let me = this;
65bb3b67
DC
213 me.loadTask.cancel();
214 Ext.TaskManager.stop(me.task);
de2e10b5
DM
215 },
216
65bb3b67
DC
217 // for user to initiate a load from outside
218 requestUpdate: function() {
05a977a2 219 let me = this;
65bb3b67
DC
220 me.loadTask.delay(200);
221 },
de2e10b5 222
65bb3b67
DC
223 viewModel: {
224 data: {
225 until: null,
226 since: null,
227 hide_timespan: false,
228 data: {
229 start: 0,
230 total: 0,
01031528 231 textlen: 0,
65bb3b67
DC
232 },
233 params: {
234 start: 0,
4e95d1e9 235 limit: 510,
01031528
TL
236 },
237 },
65bb3b67 238 },
de2e10b5 239
65bb3b67
DC
240 layout: 'auto',
241 bodyPadding: 5,
242 scrollable: {
243 x: 'auto',
244 y: 'auto',
245 listeners: {
a16b036b
TL
246 // we have to have this here, since we cannot listen to events of the scroller in
247 // the viewcontroller (extjs bug?), nor does the panel have a 'scroll' event'
65bb3b67
DC
248 scroll: {
249 fn: function(scroller, x, y) {
05a977a2 250 let controller = this.component.getController();
65bb3b67 251 if (controller) { // on destroy, controller can be gone
01031528 252 controller.onScroll(x, y);
65bb3b67
DC
253 }
254 },
01031528 255 buffer: 200,
65bb3b67 256 },
01031528 257 },
65bb3b67 258 },
de2e10b5 259
65bb3b67
DC
260 tbar: {
261 bind: {
01031528 262 hidden: '{hide_timespan}',
65bb3b67
DC
263 },
264 items: [
265 '->',
266 'Since: ',
267 {
268 xtype: 'datefield',
269 name: 'since_date',
270 reference: 'since',
271 format: 'Y-m-d',
272 bind: {
273 value: '{since}',
01031528
TL
274 maxValue: '{until}',
275 },
de2e10b5 276 },
65bb3b67
DC
277 'Until: ',
278 {
279 xtype: 'datefield',
280 name: 'until_date',
281 reference: 'until',
282 format: 'Y-m-d',
283 bind: {
284 value: '{until}',
01031528
TL
285 minValue: '{since}',
286 },
65bb3b67
DC
287 },
288 {
289 xtype: 'button',
290 text: 'Update',
01031528
TL
291 handler: 'updateParams',
292 },
65bb3b67
DC
293 ],
294 },
de2e10b5 295
65bb3b67
DC
296 items: [
297 {
298 xtype: 'box',
299 reference: 'content',
300 style: {
301 font: 'normal 11px tahoma, arial, verdana, sans-serif',
01031528 302 'white-space': 'pre',
65bb3b67 303 },
01031528
TL
304 },
305 ],
de2e10b5 306});