]> git.proxmox.com Git - pmg-gui.git/blame - js/MailTracker.js
try using 'pve-eslint' if it exists
[pmg-gui.git] / js / MailTracker.js
CommitLineData
cf248533
DM
1Ext.define('pmg-mail-tracker', {
2 extend: 'Ext.data.Model',
3 fields: [
c87d46fb 4 'id', 'from', 'to', 'dstatus', 'rstatus', 'qid', 'msgid', 'client',
cf248533 5 { type: 'number', name: 'size' },
c87d46fb 6 { type: 'date', dateFormat: 'timestamp', name: 'time' },
cf248533
DM
7 ],
8 proxy: {
c87d46fb 9 type: 'proxmox',
cf248533 10 },
9bde3d85
DM
11 // do not use field 'id', because "id/to" is the unique Id
12 // this way we display an entry for each receiver
c87d46fb 13 idProperty: 'none',
cf248533
DM
14});
15
16
17Ext.define('PMG.MailTrackerFilter', {
18 extend: 'Ext.container.Container',
19 xtype: 'pmgMailTrackerFilter',
20
21 layout: {
c87d46fb 22 type: 'hbox',
cf248533
DM
23 },
24
25 controller: {
26
27 xclass: 'Ext.app.ViewController',
28
29 onFilterChange: function() {
28eb60c0 30 let view = this.getView();
cf248533
DM
31 view.fireEvent('filterChanged');
32 },
33
34 onSpecialKey: function(field, e) {
28eb60c0 35 if (e.getKey() === e.ENTER) {
cf248533
DM
36 this.onFilterChange();
37 }
c87d46fb 38 },
cf248533
DM
39 },
40
6f3f8ac5
DC
41 viewModel: {},
42
cf248533 43 getFilterParams: function() {
28eb60c0
TL
44 let me = this;
45 let param = {};
cf248533 46
28eb60c0 47 let names = ['from', 'target', 'xfilter', 'starttime', 'endtime', 'ndr', 'greylist'];
cf248533 48 Ext.Array.each(names, function(name) {
28eb60c0 49 let value = me.lookupReference(name).getSubmitValue();
cf248533
DM
50 if (value) { param[name] = value; }
51 });
52
e8e332fe
DC
53 // there must always be a start and endtime, otherwise the field was invalid
54 if (!param.starttime || !param.endtime) {
55 return undefined;
56 }
cf248533
DM
57 return param;
58 },
59
60 items: [
61 {
62 width: 400,
63 border: false,
64 padding: 10,
65 layout: {
66 type: 'vbox',
c87d46fb 67 align: 'stretch',
cf248533
DM
68 },
69 items: [
70 {
71 fieldLabel: gettext('Sender'),
72 xtype: 'textfield',
73 listeners: { specialkey: 'onSpecialKey' },
c87d46fb 74 reference: 'from',
cf248533
DM
75 },
76 {
77 fieldLabel: gettext('Receiver'),
78 xtype: 'textfield',
79 listeners: { specialkey: 'onSpecialKey' },
c87d46fb 80 reference: 'target',
cf248533
DM
81 },
82 {
83 fieldLabel: gettext('Filter'),
84 xtype: 'textfield',
85 listeners: { specialkey: 'onSpecialKey' },
c87d46fb
TL
86 reference: 'xfilter',
87 },
88 ],
cf248533
DM
89 },
90 {
cf248533
DM
91 border: false,
92 padding: 10,
93 layout: {
94 type: 'vbox',
c87d46fb 95 align: 'stretch',
cf248533
DM
96 },
97 items: [
98 {
99 fieldLabel: gettext('Start'),
100 reference: 'starttime',
2e330d44
DC
101 listeners: {
102 change: {
103 fn: 'onFilterChange',
104 buffer: 500,
105 },
106 },
cf248533 107 value: (function() {
28eb60c0 108 let now = new Date();
cf248533 109 return new Date(now.getTime() - 3600000);
be95ef5d 110 }()),
c87d46fb 111 xtype: 'promxoxDateTimeField',
cf248533
DM
112 },
113 {
114 fieldLabel: gettext('End'),
115 reference: 'endtime',
2e330d44
DC
116 listeners: {
117 change: {
118 fn: 'onFilterChange',
119 buffer: 500,
120 },
121 },
00ac25c1 122 value: (function() {
28eb60c0
TL
123 let now = new Date();
124 let tomorrow = new Date();
00ac25c1
DM
125 tomorrow.setDate(now.getDate()+1);
126 tomorrow.setHours(0);
127 tomorrow.setMinutes(0);
128 tomorrow.setSeconds(0);
129 return tomorrow;
130 }()),
c87d46fb 131 xtype: 'promxoxDateTimeField',
cf248533
DM
132 },
133 {
de0ebd99 134 layout: {
c87d46fb 135 type: 'hbox',
de0ebd99 136 },
cf248533
DM
137 border: false,
138 items: [
139 {
d545f59e 140 boxLabel: gettext('Include Empty Senders'),
cf248533
DM
141 xtype: 'proxmoxcheckbox',
142 listeners: { change: 'onFilterChange' },
143 reference: 'ndr',
c87d46fb 144 name: 'ndrs',
cf248533
DM
145 },
146 {
147 boxLabel: gettext('Include Greylist'),
148 xtype: 'proxmoxcheckbox',
149 listeners: { change: 'onFilterChange' },
150 margin: { left: 20 },
151 reference: 'greylist',
c87d46fb
TL
152 name: 'greylist',
153 },
154 ],
155 },
156 ],
157 },
158 ],
cf248533
DM
159});
160
161Ext.define('PMG.MaiLogWindow', {
162 extend: 'Ext.window.Window',
163 xtype: 'pmgMaiLogWindow',
164
165 title: gettext('Syslog'),
166
167 logid: undefined,
168 starttime: undefined,
169 endtime: undefined,
170
171 width: 1024,
172 height: 400,
173 scrollable: true,
174
de0ebd99 175 layout: {
c87d46fb 176 type: 'auto',
de0ebd99 177 },
cf248533
DM
178 modal: true,
179 bodyPadding: 5,
180
181 load: function() {
28eb60c0 182 let me = this;
cf248533
DM
183
184 Proxmox.Utils.API2Request({
185 method: 'GET',
186 params: { starttime: me.starttime, endtime: me.endtime },
187 url: '/nodes/' + Proxmox.NodeName + '/tracker/' + me.logid,
188 waitMsgTarget: me,
189 failure: function(response, opts) {
190 me.update(gettext('Error') + " " + response.htmlStatus);
191 },
192 success: function(response, opts) {
28eb60c0 193 let data = response.result.data;
cf248533 194
28eb60c0 195 let logs = "<pre style='margin: 0;'>";
cf248533
DM
196 Ext.Array.each(data.logs, function(line) {
197 logs += Ext.htmlEncode(line) + "\n";
198 });
199 logs += "</pre>";
200 me.update(logs);
c87d46fb 201 },
cf248533
DM
202 });
203 },
204
c87d46fb 205 initComponent: function() {
28eb60c0 206 let me = this;
cf248533
DM
207
208 if (!me.logid) {
209 throw "no logid specified";
210 }
211
212 if (!me.starttime) {
213 throw "no starttime specified";
214 }
215 if (!me.endtime) {
216 throw "no endtime specified";
217 }
218
219 me.callParent();
220
221 me.setHtml('Loading...');
222 me.load();
c87d46fb 223 },
cf248533
DM
224});
225
226Ext.define('PMG.MailTracker', {
227 extend: 'Ext.grid.GridPanel',
228 xtype: 'pmgMailTracker',
229
230 title: gettext('Tracking Center'),
231
232 border: false,
233
23959bb0 234 emptyText: gettext("Please enter your search parameters and press 'Search'."),
0960034c
DC
235 disableSelection: true,
236
cf248533 237 viewConfig: {
0960034c
DC
238 deferEmptyText: false,
239 enableTextSelection: true,
dd502c64 240 getRowClass: function(record, index) {
28eb60c0 241 let status = record.data.rstatus || record.data.dstatus;
dd502c64 242 return PMG.Utils.mail_status_map[status];
c87d46fb 243 },
cf248533
DM
244 },
245
0960034c
DC
246 plugins: [
247 {
248 ptype: 'rowexpander',
b5314633 249 expandOnDblClick: false,
c87d46fb
TL
250 rowBodyTpl: '<p class="logs">{logs}</p>',
251 },
0960034c
DC
252 ],
253
cf248533
DM
254 store: {
255 autoDestroy: true,
3d309d74
DC
256 model: 'pmg-mail-tracker',
257 sorters: 'time',
cf248533
DM
258 },
259
260 controller: {
261
262 xclass: 'Ext.app.ViewController',
263
264 onSearch: function() {
28eb60c0 265 let view = this.getView();
23959bb0 266 view.setEmptyText(gettext('No data in database'));
28eb60c0
TL
267 let filter = this.lookupReference('filter');
268 let status = this.lookupReference('status');
269 let params = filter.getFilterParams();
e8e332fe
DC
270 if (params === undefined) {
271 return; // something went wrong with the filters bail out
272 }
cf248533
DM
273 status.update(''); // clear status before load
274 view.store.proxy.setExtraParams(params);
275 view.store.proxy.setUrl('/api2/json/nodes/' + Proxmox.NodeName + '/tracker');
276 view.store.load(function(records, operation, success) {
28eb60c0 277 let response = operation.getResponse();
cf248533
DM
278 if (success) {
279 // fixme: howto avoid duplicate Ext.decode ?
28eb60c0 280 let result = Ext.decode(response.responseText);
cf248533
DM
281 if (result.changes) {
282 status.update(result.changes);
283 }
284 }
285 });
286 },
287
0960034c 288 showDetails: function(rowNode, record) {
28eb60c0 289 let view = this.getView();
cf248533 290
28eb60c0 291 let params = view.store.proxy.getExtraParams();
cf248533 292
0960034c
DC
293 Proxmox.Utils.API2Request({
294 method: 'GET',
295 params: { starttime: params.starttime, endtime: params.endtime },
296 url: '/nodes/' + Proxmox.NodeName + '/tracker/' + record.data.id,
297 waitMsgTarget: view,
298 failure: function(response, opts) {
c87d46fb 299 record.set('logs', gettext('Error') + " " + response.htmlStatus);
0960034c
DC
300 },
301 success: function(response, opts) {
28eb60c0
TL
302 let data = response.result.data;
303 let logs = "";
0960034c
DC
304
305 Ext.Array.each(data.logs, function(line) {
306 logs += Ext.htmlEncode(line) + "<br>";
307 });
308
309 record.set('logs', logs);
c87d46fb 310 },
cf248533 311 });
0960034c
DC
312 },
313
b5314633
DC
314 // only expand row on dblclick, but do not collapse
315 expand: function(view, record, row, rowIdx, e) {
316 // inspired by RowExpander.js
317 let rowNode = view.getNode(rowIdx);
318 let normalRow = Ext.fly(rowNode);
319
320 let collapsedCls = view.rowBodyFeature.rowCollapsedCls;
321
322 if (normalRow.hasCls(collapsedCls)) {
323 view.rowBodyFeature.rowExpander.toggleRow(rowIdx, record);
324 }
325 },
326
0960034c
DC
327 control: {
328 'gridview': {
b5314633
DC
329 expandbody: 'showDetails',
330 itemdblclick: 'expand',
c87d46fb
TL
331 },
332 },
cf248533
DM
333 },
334
23959bb0
DC
335 // extjs has no method to dynamically change the emptytext on
336 // grids, so we have to do it this way
337 setEmptyText: function(emptyText) {
338 let me = this;
339 let tableview = me.getView();
340 tableview.emptyText = `<div class="x-grid-empty">${emptyText || ""}</div>`;
341 },
342
cf248533
DM
343 dockedItems: [
344 {
345 xtype: 'pmgMailTrackerFilter',
346 reference: 'filter',
c87d46fb 347 listeners: { filterChanged: 'onSearch' },
cf248533 348 border: false,
c87d46fb 349 dock: 'top',
cf248533
DM
350 },
351 {
352 xtype: 'toolbar',
353 items: [
354 { text: 'Search', handler: 'onSearch' },
c87d46fb
TL
355 { xtype: 'component', html: '', reference: 'status' },
356 ],
357 },
cf248533
DM
358 ],
359
360 columns: [
361 {
362 xtype: 'datecolumn',
363 header: gettext('Time'),
364 width: 120,
365 dataIndex: 'time',
c87d46fb 366 format: 'M d H:i:s',
cf248533
DM
367 },
368 {
369 header: gettext('From'),
370 flex: 1,
07d37f59 371 dataIndex: 'from',
c87d46fb 372 renderer: Ext.htmlEncode,
cf248533
DM
373 },
374 {
375 header: gettext('To'),
376 flex: 1,
07d37f59 377 dataIndex: 'to',
c87d46fb 378 renderer: Ext.htmlEncode,
cf248533
DM
379 },
380 {
381 header: gettext('Status'),
382 width: 150,
383 renderer: function(v, metaData, rec) {
28eb60c0
TL
384 let returntext = 'unknown';
385 let icon = 'question-circle';
386 let rstatus = rec.data.rstatus;
cf248533 387 if (v !== undefined && v !== '') {
28eb60c0 388 let vtext = PMG.Utils.mail_status_map[v] || v;
dd502c64 389 icon = v;
d42f76fc
DM
390 if (v === 'Q' || v === 'B') {
391 returntext = vtext;
c87d46fb 392 } else if (rstatus !== undefined && rstatus !== '') {
28eb60c0 393 let rtext = PMG.Utils.mail_status_map[rstatus] || rstatus;
dd502c64
DC
394 returntext = vtext + '/' + rtext;
395 icon = rstatus;
396 } else if (rec.data.qid !== undefined) {
397 returntext = 'queued/' + vtext;
398 } else {
399 returntext = vtext;
cf248533 400 }
cf248533 401 }
dd502c64
DC
402
403 return PMG.Utils.format_status_icon(icon) + returntext;
cf248533 404 },
c87d46fb 405 dataIndex: 'dstatus',
cf248533
DM
406 },
407 {
408 header: gettext('Size'),
409 hidden: true,
c87d46fb 410 dataIndex: 'size',
cf248533
DM
411 },
412 {
413 header: 'MSGID',
414 width: 300,
415 hidden: true,
07d37f59 416 dataIndex: 'msgid',
c87d46fb 417 renderer: Ext.htmlEncode,
cf248533
DM
418 },
419 {
420 header: gettext('Client'),
421 width: 200,
422 hidden: true,
07d37f59 423 dataIndex: 'client',
c87d46fb
TL
424 renderer: Ext.htmlEncode,
425 },
cf248533
DM
426 ],
427
cf248533 428 initComponent: function() {
28eb60c0 429 let me = this;
cf248533
DM
430
431 me.callParent();
432
433 Proxmox.Utils.monStoreErrors(me.getView(), me.store);
c87d46fb 434 },
cf248533 435});