]> git.proxmox.com Git - pmg-gui.git/blob - js/QuarantineList.js
fix #4238: spam info grid: enable sorting & add colors for spam score
[pmg-gui.git] / js / QuarantineList.js
1 Ext.define('PMG.QuarantineList', {
2 extend: 'Ext.grid.GridPanel',
3 xtype: 'pmgQuarantineList',
4
5 emptyText: gettext('No E-Mail address selected'),
6 viewConfig: {
7 deferEmptyText: false,
8 },
9
10 config: {
11 emailSelection: false,
12 notFoundText: gettext('No data in database'),
13 },
14
15 statics: {
16 from: 0,
17 to: 0,
18 },
19
20 allowPositionSave: false,
21
22 controller: {
23 xclass: 'Ext.app.ViewController',
24
25 init: function(view) {
26 let me = this;
27 if (PMG.view === 'quarantineview') {
28 view.emailSelection = false;
29 me.setEmptyText();
30 }
31 let emailCombobox = me.lookupReference('email');
32 emailCombobox.setVisible(view.emailSelection);
33 emailCombobox.setDisabled(!view.emailSelection);
34
35 let from;
36 if (PMG.QuarantineList.from !== 0) {
37 from = new Date(PMG.QuarantineList.from * 1000);
38 } else {
39 from = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);
40 }
41
42 let to;
43 if (PMG.QuarantineList.to !== 0) {
44 to = new Date(PMG.QuarantineList.to * 1000);
45 } else {
46 to = new Date();
47 }
48
49 // we to this to trigger the change event of those fields
50 me.lookupReference('from').setValue(from);
51 me.lookupReference('to').setValue(to);
52
53 Proxmox.Utils.monStoreErrors(view.getView(), view.getStore());
54 me.load(function() {
55 if (view.cselect) {
56 view.setSelection(view.getStore().getById(view.cselect));
57 }
58 });
59 },
60 // ExtJS cannot dynamically change the emptyText on grids, so implement ourself
61 setEmptyText: function(emptyText) {
62 let me = this;
63 let view = me.getView();
64 let tableview = view.getView();
65 tableview.emptyText = `<div class="x-grid-empty">${emptyText || view.notFoundText}</div>`;
66 },
67
68 load: function(callback) {
69 let me = this;
70 me.allowPositionSave = false;
71 let view = me.getView();
72 let store = view.getStore();
73 if (view.emailSelection) {
74 if (!me.lookupReference('email').getSelection()) {
75 return; // if the combobox has no selection we do not reload
76 }
77 me.setEmptyText();
78 }
79 // deselect all first, else ExtJS does some funky O(n^3) comparissions as it tries
80 // to keep the selection, but we do not care for that on a new load anyway
81 view.getSelectionModel().deselectAll();
82
83 store.load(() => {
84 me.restoreSavedSelection();
85 if (Ext.isFunction(callback)) {
86 callback();
87 }
88 me.allowPositionSave = true;
89 });
90 },
91
92 restoreSavedSelection: function() {
93 let me = this;
94 let view = me.getView();
95 if (me.savedPosition !== undefined) {
96 let store = view.getStore();
97 if (store.getCount() - 1 < me.savedPosition) {
98 me.savedPosition = store.getCount() - 1;
99 }
100 view.setSelection(store.getAt(me.savedPosition));
101 } else {
102 view.setSelection();
103 }
104 },
105
106 setFrom: function(from) {
107 let view = this.getView();
108 let params = view.getStore().getProxy().getExtraParams();
109 params.starttime = from;
110 PMG.QuarantineList.from = from;
111 view.getStore().getProxy().setExtraParams(params);
112 },
113
114 setTo: function(to) {
115 let end_of_to = to + 24*60*60; // we want the end of the day
116 let view = this.getView();
117 let params = view.getStore().getProxy().getExtraParams();
118 params.endtime = end_of_to;
119 PMG.QuarantineList.to = to; // we save the start of the day here
120 view.getStore().getProxy().setExtraParams(params);
121 },
122
123 setUser: function(user) {
124 let view = this.getView();
125 let params = view.getStore().getProxy().getExtraParams();
126 if (user === null) {
127 delete params.pmail;
128 } else {
129 params.pmail = user;
130 }
131 view.getStore().getProxy().setExtraParams(params);
132 view.user = user;
133 },
134
135 changeTime: function(field, value) {
136 let me = this;
137
138 me.allowPositionSave = false;
139 me.savedPosition = undefined;
140
141 if (!value) {
142 return;
143 }
144
145 let val = value.getTime() / 1000;
146 let combobox = me.lookupReference('email');
147 let params = combobox.getStore().getProxy().getExtraParams();
148
149 let to = me.lookupReference('to');
150 let from = me.lookupReference('from');
151
152 if (field.name === 'from') {
153 me.setFrom(val);
154 params.starttime = val;
155 to.setMinValue(value);
156 } else if (field.name === 'to') {
157 me.setTo(val);
158 params.endtime = val + 24*60*60;
159 from.setMaxValue(value);
160 } else {
161 return;
162 }
163
164 combobox.getStore().getProxy().setExtraParams(params);
165 combobox.getStore().load();
166
167 me.load();
168 },
169
170 resetEmail: function() {
171 let me = this;
172 let view = me.getView();
173 if (view.emailSelection) {
174 me.setUser(undefined);
175 }
176 },
177
178 changeEmail: function(tb, value) {
179 let me = this;
180 me.savedPosition = undefined;
181 me.allowPositionSave = false;
182 if (value === 'all') {
183 me.setUser(null);
184 } else {
185 me.setUser(value);
186 }
187 me.load();
188 },
189
190 savePosition: function(grid, selected, eopts) {
191 let me = this;
192 if (!me.allowPositionSave) {
193 return;
194 }
195 if (selected.length <= 0) {
196 me.savedPosition = undefined;
197 return;
198 }
199
200 let view = me.getView();
201 let id = view.getStore().indexOf(selected[0]);
202
203 me.savedPosition = id;
204 },
205
206 doFilter: function(searchValue, store, sm) {
207 const selected = sm.getSelection();
208 const selectedRecordId = selected.length === 1 ? selected[0].id : null;
209 let clearSelectedMail = true;
210 let toDeselect = [];
211 store.filterBy(function(record) {
212 let match = false;
213
214 Ext.each(['subject', 'from'], property => {
215 if (record.data[property] === null) {
216 return;
217 }
218
219 let v = record.data[property].toString();
220 if (v !== undefined) {
221 v = v.toLowerCase();
222 if (v.includes(searchValue)) {
223 match = true;
224 if (record.id === selectedRecordId) {
225 clearSelectedMail = false;
226 }
227 }
228 }
229 });
230 if (!match && sm.isSelected(record)) {
231 toDeselect.push(record);
232 }
233 return match;
234 });
235 if (toDeselect.length > 0) {
236 sm.deselect(toDeselect, true);
237 sm.maybeFireSelectionChange(true);
238 }
239 return selectedRecordId !== null && clearSelectedMail;
240 },
241
242 updateFilter: async function(field) {
243 let me = this;
244 let view = me.getView();
245 let store = view.getStore();
246 let sm = view.getSelectionModel();
247
248 let searchValue = field.getValue().toLowerCase();
249
250 // supress store event if not empty, let filterBy below trigger it to avoid glitches
251 store.clearFilter(searchValue.length > 0);
252 field.triggers.clear.setVisible(searchValue.length > 0);
253
254 if (searchValue.length === 0) {
255 me.setEmptyText();
256 return;
257 }
258 me.setEmptyText(gettext('No match found'));
259
260 let clearSelection = me.doFilter(searchValue, store, sm);
261
262 if (clearSelection) {
263 view.setSelection();
264 }
265 },
266
267 control: {
268 '#': {
269 beforedestroy: 'resetEmail',
270 selectionchange: 'savePosition',
271 },
272 'combobox[reference=email]': {
273 change: 'changeEmail',
274 },
275 datefield: {
276 change: {
277 fn: 'changeTime',
278 },
279 },
280
281 },
282 },
283
284 features: [
285 {
286 ftype: 'grouping',
287 groupHeaderTpl: '{columnName}: {name} ({children.length})',
288 },
289 ],
290
291 tbar: {
292 layout: {
293 type: 'vbox',
294 align: 'stretch',
295 },
296 defaults: {
297 margin: 2,
298 },
299 items: [
300 {
301 xtype: 'datefield',
302 name: 'from',
303 fieldLabel: gettext('Since'),
304 reference: 'from',
305 format: 'Y-m-d',
306 },
307 {
308 xtype: 'datefield',
309 name: 'to',
310 fieldLabel: gettext('Until'),
311 reference: 'to',
312 format: 'Y-m-d',
313 },
314 {
315 xtype: 'combobox',
316 hidden: true,
317 displayField: 'mail',
318 valueField: 'mail',
319 listConfig: {
320 emptyText:
321 '<div class="x-grid-empty">' +
322 gettext('No data in database') +
323 '</div>',
324 },
325 store: {
326 proxy: {
327 type: 'proxmox',
328 url: '/api2/json/quarantine/spamusers',
329 },
330 fields: [
331 {
332 name: 'mail',
333 renderer: Ext.htmlEncode,
334 },
335 ],
336 listeners: {
337 load: function(store, records, successfull) {
338 if (successfull && records.length > 1) {
339 store.insert(0, { mail: 'all' });
340 }
341 },
342 },
343 },
344 queryMode: 'local',
345 editable: true,
346 typeAhead: true,
347 forceSelection: true,
348 autoSelect: true,
349 anyMatch: true,
350 selectOnFocus: true,
351 reference: 'email',
352 fieldLabel: 'E-Mail',
353 },
354 {
355 xtype: 'textfield',
356 name: 'filter',
357 fieldLabel: gettext('Search'),
358 emptyText: gettext('Subject, Sender'),
359 enableKeyEvents: true,
360 triggers: {
361 clear: {
362 cls: 'pmx-clear-trigger',
363 weight: -1,
364 hidden: true,
365 handler: function() {
366 let me = this;
367 me.setValue('');
368 // setValue does not results in a keyup event, so trigger manually
369 me.up('grid').getController().updateFilter(me);
370 },
371 },
372 },
373 listeners: {
374 buffer: 500,
375 keyup: 'updateFilter',
376 },
377 },
378 ],
379 },
380 });