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