mirror of
https://git.proxmox.com/git/pmg-gui
synced 2025-05-01 04:04:23 +00:00

A separate header and docked at the bottom reduces crowding at the top and make the whole view(s) a bit clearer. This also better mirrors where most mail clients show attachments (e.g., thunderbird) and allows to avoid the extra button (UX benefits most of the time from reduced inputs, if it doesn't takes away features). Make the panel collapsible for the spam and virus quarantine, and hide the download button there; note that this isn't done for security purpose but just wasn't requested and some users may do better if they only decide deliver/delete here and let their MUA handle attachements. Disable collapsing in the Attachement quarantine, it doesn't really makes sense there and we got a maxHeight already anyway. Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
174 lines
4.8 KiB
JavaScript
174 lines
4.8 KiB
JavaScript
Ext.define('PMG.controller.QuarantineController', {
|
|
extend: 'Ext.app.ViewController',
|
|
alias: 'controller.quarantine',
|
|
|
|
updatePreview: function(raw, rec) {
|
|
let preview = this.lookupReference('preview');
|
|
|
|
if (!rec || !rec.data || !rec.data.id) {
|
|
preview.update('');
|
|
preview.setDisabled(true);
|
|
return;
|
|
}
|
|
|
|
let url = `/api2/htmlmail/quarantine/content?id=${rec.data.id}`;
|
|
if (raw) {
|
|
url += '&raw=1';
|
|
}
|
|
preview.setDisabled(false);
|
|
this.lookupReference('raw').setDisabled(false);
|
|
this.lookupReference('download').setDisabled(false);
|
|
preview.update("<iframe frameborder=0 width=100% height=100% sandbox='allow-same-origin' src='" + url +"'></iframe>");
|
|
},
|
|
|
|
multiSelect: function(selection) {
|
|
let me = this;
|
|
me.lookupReference('raw').setDisabled(true);
|
|
me.lookupReference('download').setDisabled(true);
|
|
me.lookupReference('mailinfo').setVisible(false);
|
|
me.lookup('attachmentlist')?.setVisible(false);
|
|
|
|
let preview = me.lookupReference('preview');
|
|
preview.setDisabled(false);
|
|
preview.update(`<h3 style="padding-left:5px;">${gettext('Multiple E-Mails selected')} (${selection.length})</h3>`);
|
|
},
|
|
|
|
toggleRaw: function(button) {
|
|
let me = this;
|
|
let list = me.lookupReference('list');
|
|
let rec = list.selModel.getSelection()[0];
|
|
me.lookupReference('mailinfo').setVisible(me.raw);
|
|
me.raw = !me.raw;
|
|
me.updatePreview(me.raw, rec);
|
|
},
|
|
|
|
btnHandler: function(button, e) {
|
|
let me = this;
|
|
let action = button.reference;
|
|
let list = me.lookupReference('list');
|
|
let selected = list.getSelection();
|
|
me.doAction(action, selected);
|
|
},
|
|
|
|
doAction: function(action, selected) {
|
|
if (!selected.length) {
|
|
return;
|
|
}
|
|
|
|
let list = this.lookupReference('list');
|
|
|
|
if (selected.length > 1) {
|
|
let idlist = selected.map(item => item.data.id);
|
|
Ext.Msg.confirm(
|
|
gettext('Confirm'),
|
|
Ext.String.format(
|
|
gettext("Action '{0}' for '{1}' items"),
|
|
action, selected.length,
|
|
),
|
|
async function(button) {
|
|
if (button !== 'yes') {
|
|
return;
|
|
}
|
|
|
|
list.mask(gettext('Processing...'), 'x-mask-loading');
|
|
|
|
const sliceSize = 2500, maxInFlight = 2;
|
|
let batches = [], batchCount = Math.ceil(selected.length / sliceSize);
|
|
for (let i = 0; i * sliceSize < selected.length; i++) {
|
|
let sliceStart = i * sliceSize;
|
|
let sliceEnd = Math.min(sliceStart + sliceSize, selected.length);
|
|
batches.push(
|
|
PMG.Async.doQAction(
|
|
action,
|
|
idlist.slice(sliceStart, sliceEnd),
|
|
i + 1,
|
|
batchCount,
|
|
),
|
|
);
|
|
if (batches.length >= maxInFlight) {
|
|
await Promise.allSettled(batches); // eslint-disable-line no-await-in-loop
|
|
batches = [];
|
|
}
|
|
}
|
|
await Promise.allSettled(batches); // await possible remaining ones
|
|
list.unmask();
|
|
// below can be slow, we could remove directly from the in-memory store, but
|
|
// with lots of elements and some failures we could be quite out of sync?
|
|
list.getController().load();
|
|
},
|
|
);
|
|
return;
|
|
}
|
|
|
|
PMG.Utils.doQuarantineAction(action, selected[0].data.id, function() {
|
|
let listController = list.getController();
|
|
listController.allowPositionSave = false;
|
|
// success -> remove directly to avoid slow store reload for a single-element action
|
|
list.getStore().remove(selected[0]);
|
|
listController.restoreSavedSelection();
|
|
listController.allowPositionSave = true;
|
|
});
|
|
},
|
|
|
|
onSelectMail: function() {
|
|
let me = this;
|
|
let list = this.lookupReference('list');
|
|
let selection = list.selModel.getSelection();
|
|
if (selection.length > 1) {
|
|
me.multiSelect(selection);
|
|
return;
|
|
}
|
|
|
|
let rec = selection[0] || {};
|
|
me.lookup('spaminfo')?.setID(rec);
|
|
me.lookup('attachmentlist')?.setID(rec);
|
|
me.lookup('attachmentlist')?.setVisible(!!rec.data);
|
|
|
|
me.getViewModel().set('mailid', rec.data ? rec.data.id : '');
|
|
me.updatePreview(me.raw || false, rec);
|
|
me.lookupReference('mailinfo').setVisible(!!rec.data && !me.raw);
|
|
me.lookupReference('mailinfo').update(rec.data);
|
|
},
|
|
|
|
openContextMenu: function(table, record, tr, index, event) {
|
|
event.stopEvent();
|
|
let me = this;
|
|
let list = me.lookup('list');
|
|
Ext.create('PMG.menu.QuarantineContextMenu', {
|
|
callback: action => me.doAction(action, list.getSelection()),
|
|
}).showAt(event.getXY());
|
|
},
|
|
|
|
keyPress: function(table, record, item, index, event) {
|
|
let me = this;
|
|
let list = me.lookup('list');
|
|
let key = event.getKey();
|
|
let action = '';
|
|
switch (key) {
|
|
case event.DELETE:
|
|
case 127:
|
|
action = 'delete';
|
|
break;
|
|
case Ext.event.Event.D:
|
|
case Ext.event.Event.D + 32:
|
|
action = 'deliver';
|
|
break;
|
|
}
|
|
|
|
if (action !== '') {
|
|
me.doAction(action, list.getSelection());
|
|
}
|
|
},
|
|
|
|
control: {
|
|
'button[reference=raw]': {
|
|
click: 'toggleRaw',
|
|
},
|
|
'pmgQuarantineList': {
|
|
selectionChange: 'onSelectMail',
|
|
itemkeypress: 'keyPress',
|
|
rowcontextmenu: 'openContextMenu',
|
|
},
|
|
},
|
|
});
|