public inbox for pmg-devel@lists.proxmox.com
 help / color / mirror / Atom feed
* [pmg-devel] [PATCH pmg-gui v2 0/2] low-hanging improvments for the quarantine interface
@ 2022-10-27 19:12 Stoiko Ivanov
  2022-10-27 19:12 ` [pmg-devel] [PATCH pmg-gui v2 1/2] quarantine: refactor spamquarantine controller Stoiko Ivanov
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Stoiko Ivanov @ 2022-10-27 19:12 UTC (permalink / raw)
  To: pmg-devel

v1->v2:
* dropped already applied patches
* changed the patches, by splitting the refactoring of the spamquarantine
  in a patch of its own, and changing virus and attachmentquarantine in
  the second patch (no functional change intended) - big thanks for the
  suggestion @Thomas!!

gave me also the chance to see the adaptations of the icon-colors for delivery
and delete by Thomas in action - I like it!

original cover-letter for v1:
A few bugzilla entries ask for features in the quarantine interface that
seem quite sensible (e.g. #4137), or are already present in the (by far
more used) spamquarantine, but never made it to the others.

This patchset contains a single small fix, and a refactoring of the
quarantine views to use the same controller.

Would be grateful for feedback


Stoiko Ivanov (2):
  quarantine: refactor spamquarantine controller
  quarantine: use new controller for virus and attachment quarantines

 js/AttachmentQuarantine.js            | 113 +++++-----
 js/Makefile                           |   1 +
 js/SpamQuarantine.js                  | 290 +++++++++-----------------
 js/VirusQuarantine.js                 |  86 ++------
 js/controller/QuarantineController.js | 170 +++++++++++++++
 5 files changed, 335 insertions(+), 325 deletions(-)
 create mode 100644 js/controller/QuarantineController.js

-- 
2.30.2





^ permalink raw reply	[flat|nested] 4+ messages in thread

* [pmg-devel] [PATCH pmg-gui v2 1/2] quarantine: refactor spamquarantine controller
  2022-10-27 19:12 [pmg-devel] [PATCH pmg-gui v2 0/2] low-hanging improvments for the quarantine interface Stoiko Ivanov
@ 2022-10-27 19:12 ` Stoiko Ivanov
  2022-10-27 19:12 ` [pmg-devel] [PATCH pmg-gui v2 2/2] quarantine: use new controller for virus and attachment quarantines Stoiko Ivanov
  2022-10-28  9:35 ` [pmg-devel] applied-series: Re: [PATCH pmg-gui v2 0/2] low-hanging improvments for the quarantine interface Thomas Lamprecht
  2 siblings, 0 replies; 4+ messages in thread
From: Stoiko Ivanov @ 2022-10-27 19:12 UTC (permalink / raw)
  To: pmg-devel

over the time the spam quarantine has gained quite a few nice
usability improvments and features, which would be useful in
the virus and attachment quarantines as well - e.g.:

* multi-mail selection
* keyboard actions
* context menu
* download mail as .eml

this patch splits the controller part into a file of its own, while changing
'var' to 'let' and removing the parts only relevant for the spamquarantine
and adapts the current SpamQuarantine.js to use it.

Signed-off-by: Stoiko Ivanov <s.ivanov@proxmox.com>
---
 js/Makefile                           |   1 +
 js/SpamQuarantine.js                  | 290 +++++++++-----------------
 js/controller/QuarantineController.js | 170 +++++++++++++++
 3 files changed, 265 insertions(+), 196 deletions(-)
 create mode 100644 js/controller/QuarantineController.js

diff --git a/js/Makefile b/js/Makefile
index b904598..9a2bcf2 100644
--- a/js/Makefile
+++ b/js/Makefile
@@ -19,6 +19,7 @@ JSSRC=							\
 	RuleInfo.js					\
 	RuleEditor.js					\
 	MainView.js					\
+	controller/QuarantineController.js		\
 	QuarantineContextMenu.js			\
 	QuarantineList.js				\
 	SpamInfoGrid.js					\
diff --git a/js/SpamQuarantine.js b/js/SpamQuarantine.js
index 6fe20d7..cf7f181 100644
--- a/js/SpamQuarantine.js
+++ b/js/SpamQuarantine.js
@@ -33,225 +33,123 @@ Ext.define('pmg-spam-list', {
     idProperty: 'id',
 });
 
-Ext.define('PMG.SpamQuarantine', {
-    extend: 'Ext.container.Container',
-    xtype: 'pmgSpamQuarantine',
-
-    border: false,
-    layout: { type: 'border' },
+Ext.define('PMG.SpamQuarantineController', {
+    extend: 'PMG.controller.QuarantineController',
+    xtype: 'pmgSpamQuarantineController',
+    alias: 'controller.spamquarantine',
 
-    defaults: { border: false },
+    updatePreview: function(raw, rec) {
+	let me = this;
+	me.lookupReference('spam').setDisabled(false);
 
-    // from mail link
-    cselect: undefined,
+	me.callParent(arguments);
+    },
 
-    viewModel: {
-	parent: null,
-	data: {
-	    mailid: '',
-	},
-	formulas: {
-	    downloadMailURL: get => '/api2/json/quarantine/download?mailid=' + encodeURIComponent(get('mailid')),
-	},
+    multiSelect: function(selection) {
+	let me = this;
+	let spam = me.lookupReference('spam');
+	spam.setDisabled(true);
+	spam.setPressed(false);
+	me.lookupReference('spaminfo').setVisible(false);
+	me.callParent(selection);
     },
-    controller: {
 
-	xclass: 'Ext.app.ViewController',
+    onSelectMail: function() {
+	let me = this;
+	let list = me.lookupReference('list');
+	let selection = list.selModel.getSelection();
+	if (selection.length <= 1) {
+	    let rec = selection[0] || {};
+	    me.lookupReference('spaminfo').setID(rec);
+	}
+	me.callParent();
+    },
 
-	updatePreview: function(raw, rec) {
-	    var preview = this.lookupReference('preview');
 
-	    if (!rec || !rec.data || !rec.data.id) {
-		preview.update('');
-		preview.setDisabled(true);
-		return;
-	    }
+    toggleSpamInfo: function(btn) {
+	var grid = this.lookupReference('spaminfo');
+	grid.setVisible(!grid.isVisible());
+    },
 
-	    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('spam').setDisabled(false);
-	    this.lookupReference('download').setDisabled(false);
-	    preview.update("<iframe frameborder=0 width=100% height=100% sandbox='allow-same-origin' src='" + url +"'></iframe>");
-	},
+    openContextMenu: function(table, record, tr, index, event) {
+	event.stopEvent();
+	let me = this;
+	let list = me.lookup('list');
+	Ext.create('PMG.menu.SpamContextMenu', {
+	    callback: action => me.doAction(action, list.getSelection()),
+	}).showAt(event.getXY());
+    },
 
-	multiSelect: function(selection) {
-	    var preview = this.lookupReference('preview');
-	    var raw = this.lookupReference('raw');
-	    var spam = this.lookupReference('spam');
-	    var spaminfo = this.lookupReference('spaminfo');
-	    var mailinfo = this.lookupReference('mailinfo');
-	    var download = this.lookupReference('download');
+    keyPress: function(table, record, item, index, event) {
+	var me = this;
+	var list = me.lookup('list');
+	var key = event.getKey();
+	var 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;
+	    case Ext.event.Event.W:
+	    case Ext.event.Event.W + 32:
+		action = 'whitelist';
+		break;
+	    case Ext.event.Event.B:
+	    case Ext.event.Event.B + 32:
+		action = 'blacklist';
+		break;
+	}
 
-	    preview.setDisabled(false);
-	    preview.update(`<h3 style="padding-left:5px;">${gettext('Multiple E-Mails selected')} (${selection.length})</h3>`);
-	    raw.setDisabled(true);
-	    spam.setDisabled(true);
-	    spam.setPressed(false);
-	    spaminfo.setVisible(false);
-	    mailinfo.setVisible(false);
-	    download.setDisabled(true);
-	},
+	if (action !== '') {
+	    me.doAction(action, list.getSelection());
+	}
+    },
 
-	toggleRaw: function(button) {
-	    var me = this;
-	    var list = me.lookupReference('list');
-	    var rec = list.selModel.getSelection()[0];
-	    me.lookupReference('mailinfo').setVisible(me.raw);
-	    me.raw = !me.raw;
-	    me.updatePreview(me.raw, rec);
-	},
+    init: function(view) {
+	this.lookup('list').cselect = view.cselect;
+    },
 
-	btnHandler: function(button, e) {
-	    var me = this;
-	    var action = button.reference;
-	    var list = this.lookupReference('list');
-	    var selected = list.getSelection();
-	    me.doAction(action, selected);
+    control: {
+	'button[reference=raw]': {
+	    click: 'toggleRaw',
 	},
-
-	doAction: function(action, selected) {
-	    if (!selected.length) {
-		return;
-	    }
-
-	    var 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;
-	    });
+	'button[reference=spam]': {
+	    click: 'toggleSpamInfo',
 	},
-
-	onSelectMail: function() {
-	    var me = this;
-	    var list = this.lookupReference('list');
-	    var selection = list.selModel.getSelection();
-	    if (selection.length > 1) {
-		me.multiSelect(selection);
-		return;
-	    }
-
-	    var rec = selection[0] || {};
-
-	    me.getViewModel().set('mailid', rec.data ? rec.data.id : '');
-	    me.updatePreview(me.raw || false, rec);
-	    me.lookupReference('spaminfo').setID(rec);
-	    me.lookupReference('mailinfo').setVisible(!!rec.data && !me.raw);
-	    me.lookupReference('mailinfo').update(rec.data);
+	'pmgQuarantineList': {
+	    selectionChange: 'onSelectMail',
+	    itemkeypress: 'keyPress',
+	    rowcontextmenu: 'openContextMenu',
 	},
+    },
+});
 
-	toggleSpamInfo: function(btn) {
-	    var grid = this.lookupReference('spaminfo');
-	    grid.setVisible(!grid.isVisible());
-	},
+Ext.define('PMG.SpamQuarantine', {
+    extend: 'Ext.container.Container',
+    xtype: 'pmgSpamQuarantine',
 
-	openContextMenu: function(table, record, tr, index, event) {
-	    event.stopEvent();
-	    let me = this;
-	    let list = me.lookup('list');
-	    Ext.create('PMG.menu.SpamContextMenu', {
-		callback: action => me.doAction(action, list.getSelection()),
-	    }).showAt(event.getXY());
-	},
+    border: false,
+    layout: { type: 'border' },
 
-	keyPress: function(table, record, item, index, event) {
-	    var me = this;
-	    var list = me.lookup('list');
-	    var key = event.getKey();
-	    var 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;
-		case Ext.event.Event.W:
-		case Ext.event.Event.W + 32:
-		    action = 'whitelist';
-		    break;
-		case Ext.event.Event.B:
-		case Ext.event.Event.B + 32:
-		    action = 'blacklist';
-		    break;
-	    }
+    defaults: { border: false },
 
-	    if (action !== '') {
-		me.doAction(action, list.getSelection());
-	    }
-	},
+    // from mail link
+    cselect: undefined,
 
-	init: function(view) {
-	    this.lookup('list').cselect = view.cselect;
+    viewModel: {
+	parent: null,
+	data: {
+	    mailid: '',
 	},
-
-	control: {
-	    'button[reference=raw]': {
-		click: 'toggleRaw',
-	    },
-	    'button[reference=spam]': {
-		click: 'toggleSpamInfo',
-	    },
-	    'pmgQuarantineList': {
-		selectionChange: 'onSelectMail',
-		itemkeypress: 'keyPress',
-		rowcontextmenu: 'openContextMenu',
-	    },
+	formulas: {
+	    downloadMailURL: get => '/api2/json/quarantine/download?mailid=' + encodeURIComponent(get('mailid')),
 	},
     },
+    controller: 'spamquarantine',
 
     items: [
 	{
diff --git a/js/controller/QuarantineController.js b/js/controller/QuarantineController.js
new file mode 100644
index 0000000..dfe2915
--- /dev/null
+++ b/js/controller/QuarantineController.js
@@ -0,0 +1,170 @@
+Ext.define('PMG.controller.QuarantineController', {
+    extend: 'Ext.app.ViewController',
+    xtype: 'controller.Quarantine',
+    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);
+
+	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.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',
+	},
+    },
+});
-- 
2.30.2





^ permalink raw reply	[flat|nested] 4+ messages in thread

* [pmg-devel] [PATCH pmg-gui v2 2/2] quarantine: use new controller for virus and attachment quarantines
  2022-10-27 19:12 [pmg-devel] [PATCH pmg-gui v2 0/2] low-hanging improvments for the quarantine interface Stoiko Ivanov
  2022-10-27 19:12 ` [pmg-devel] [PATCH pmg-gui v2 1/2] quarantine: refactor spamquarantine controller Stoiko Ivanov
@ 2022-10-27 19:12 ` Stoiko Ivanov
  2022-10-28  9:35 ` [pmg-devel] applied-series: Re: [PATCH pmg-gui v2 0/2] low-hanging improvments for the quarantine interface Thomas Lamprecht
  2 siblings, 0 replies; 4+ messages in thread
From: Stoiko Ivanov @ 2022-10-27 19:12 UTC (permalink / raw)
  To: pmg-devel

fixes #1674 (the comment about multiselect for the virus quarantine)
fixes #3947 (multiselect for attachment quarantine)

Signed-off-by: Stoiko Ivanov <s.ivanov@proxmox.com>
---
 js/AttachmentQuarantine.js | 113 ++++++++++++++++---------------------
 js/VirusQuarantine.js      |  86 +++++++---------------------
 2 files changed, 70 insertions(+), 129 deletions(-)

diff --git a/js/AttachmentQuarantine.js b/js/AttachmentQuarantine.js
index 1e56420..8abfcad 100644
--- a/js/AttachmentQuarantine.js
+++ b/js/AttachmentQuarantine.js
@@ -18,87 +18,59 @@ Ext.define('pmg-attachment-list', {
     idProperty: 'id',
 });
 
-Ext.define('PMG.AttachmentQuarantine', {
-    extend: 'Ext.container.Container',
-    xtype: 'pmgAttachmentQuarantine',
-
-    border: false,
-    layout: { type: 'border' },
-
-    defaults: { border: false },
-
-    controller: {
-
-	xclass: 'Ext.app.ViewController',
-
-	updatePreview: function(raw, rec) {
-	    var preview = this.lookupReference('preview');
+Ext.define('PMG.AttachmentQuarantineController', {
+    extend: 'PMG.controller.QuarantineController',
+    alias: 'controller.attachmentquarantine',
+    xtype: 'pmgAttachmentQuarantineController',
+
+    onSelectMail: function() {
+	let me = this;
+	let list = this.lookupReference('list');
+	let selection = list.selModel.getSelection();
+	if (selection.length <= 1) {
+	    let rec = selection[0] || {};
+	    me.lookup('attachmentlist').setID(rec);
+	}
 
-	    if (!rec || !rec.data || !rec.data.id) {
-		preview.update('');
-		preview.setDisabled(true);
-		return;
-	    }
+	me.callParent();
+    },
 
-	    let url = `/api2/htmlmail/quarantine/content?id=${rec.data.id}`;
-	    if (raw) {
-		url += '&raw=1';
-	    }
-	    preview.setDisabled(false);
-	    preview.update("<iframe frameborder=0 width=100% height=100% sandbox='allow-same-origin' src='" + url +"'></iframe>");
+    control: {
+	'button[reference=raw]': {
+	    click: 'toggleRaw',
 	},
-
-	toggleRaw: function(button) {
-	    var me = this;
-	    var list = this.lookupReference('list');
-	    var rec = list.getSelection()[0] || {};
-	    me.lookup('mailinfo').setVisible(me.raw);
-	    me.raw = !me.raw;
-	    me.updatePreview(me.raw, rec);
+	'pmgQuarantineList': {
+	    selectionChange: 'onSelectMail',
 	},
+    },
 
-	btnHandler: function(button, e) {
-	    var list = this.lookupReference('list');
-	    var selected = list.getSelection();
-	    if (!selected.length) {
-		return;
-	    }
+});
 
-	    var action = button.reference;
+Ext.define('PMG.AttachmentQuarantine', {
+    extend: 'Ext.container.Container',
+    xtype: 'pmgAttachmentQuarantine',
 
-	    PMG.Utils.doQuarantineAction(action, selected[0].data.id, function() {
-		list.getController().load();
-	    });
-	},
+    border: false,
+    layout: { type: 'border' },
 
-	onSelectMail: function() {
-	    let me = this;
-	    let list = me.lookup('list');
-	    let rec = list.getSelection()[0] || {};
-	    let mailinfo = me.lookup('mailinfo');
+    defaults: { border: false },
 
-	    me.updatePreview(me.raw || false, rec);
-	    me.lookup('attachmentlist').setID(rec);
-	    mailinfo.setVisible(!!rec.data && !me.raw);
-	    mailinfo.update(rec.data);
+    viewModel: {
+	parent: null,
+	data: {
+	    mailid: '',
 	},
-
-	control: {
-	    'button[reference=raw]': {
-		click: 'toggleRaw',
-	    },
-	    'pmgQuarantineList': {
-		selectionChange: 'onSelectMail',
-	    },
+	formulas: {
+	    downloadMailURL: get => '/api2/json/quarantine/download?mailid=' + encodeURIComponent(get('mailid')),
 	},
-
     },
-
+    controller: 'attachmentquarantine',
     items: [
 	{
 	    title: gettext('Attachment Quarantine'),
 	    xtype: 'pmgQuarantineList',
 	    emptyText: gettext('No data in database'),
+	    selModel: 'checkboxmodel',
 	    emailSelection: false,
 	    reference: 'list',
 	    region: 'west',
@@ -163,6 +135,19 @@ Ext.define('PMG.AttachmentQuarantine', {
 			    iconCls: 'fa fa-file-code-o',
 			},
 			'->',
+			{
+			    xtype: 'button',
+			    reference: 'download',
+			    text: gettext('Download'),
+			    setDownload: function(id) {
+				this.el.dom.download = id + ".eml";
+			    },
+			    bind: {
+				href: '{downloadMailURL}',
+				download: '{mailid}',
+			    },
+			    iconCls: 'fa fa-download',
+			},
 			{
 			    reference: 'deliver',
 			    text: gettext('Deliver'),
diff --git a/js/VirusQuarantine.js b/js/VirusQuarantine.js
index 4c1d0ba..47e055c 100644
--- a/js/VirusQuarantine.js
+++ b/js/VirusQuarantine.js
@@ -28,80 +28,23 @@ Ext.define('PMG.VirusQuarantine', {
 
     defaults: { border: false },
 
-    controller: {
-
-	xclass: 'Ext.app.ViewController',
-
-	updatePreview: function(raw) {
-	    var list = this.lookupReference('list');
-	    var rec = list.selModel.getSelection()[0];
-	    var 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);
-	    preview.update("<iframe frameborder=0 width=100% height=100% sandbox='allow-same-origin' src='" + url +"'></iframe>");
-	},
-
-	toggleRaw: function(button) {
-	    var me = this;
-	    me.lookup('mailinfo').setVisible(me.raw);
-	    me.raw = !me.raw;
-	    me.updatePreview(me.raw);
+    viewModel: {
+	parent: null,
+	data: {
+	    mailid: '',
 	},
-
-	btnHandler: function(button, e) {
-	    var list = this.lookupReference('list');
-	    var selected = list.getSelection();
-	    if (!selected.length) {
-		return;
-	    }
-
-	    var action = button.reference;
-
-	    PMG.Utils.doQuarantineAction(action, selected[0].data.id, function() {
-		list.getController().load();
-	    });
+	formulas: {
+	    downloadMailURL: get => '/api2/json/quarantine/download?mailid=' + encodeURIComponent(get('mailid')),
 	},
-
-	onSelectMail: function() {
-	    var me = this;
-	    me.updatePreview(me.raw || false);
-	    let mailinfo = me.lookup('mailinfo');
-	    let list = me.lookup('list');
-	    let selection = list.getSelection();
-	    if (selection.length < 1) {
-		mailinfo.setVisible(false);
-		return;
-	    }
-	    mailinfo.setVisible(!me.raw);
-	    mailinfo.update(selection[0].data);
-	},
-
-	control: {
-	    'button[reference=raw]': {
-		click: 'toggleRaw',
-	    },
-	    'pmgQuarantineList': {
-		selectionChange: 'onSelectMail',
-	    },
-	},
-
     },
+    controller: 'quarantine',
 
     items: [
 	{
 	    title: gettext('Virus Quarantine'),
 	    xtype: 'pmgQuarantineList',
 	    emptyText: gettext('No data in database'),
+	    selModel: 'checkboxmodel',
 	    emailSelection: false,
 	    reference: 'list',
 	    region: 'west',
@@ -172,6 +115,19 @@ Ext.define('PMG.VirusQuarantine', {
 			    iconCls: 'fa fa-file-code-o',
 			},
 			'->',
+			{
+			    xtype: 'button',
+			    reference: 'download',
+			    text: gettext('Download'),
+			    setDownload: function(id) {
+				this.el.dom.download = id + ".eml";
+			    },
+			    bind: {
+				href: '{downloadMailURL}',
+				download: '{mailid}',
+			    },
+			    iconCls: 'fa fa-download',
+			},
 			{
 			    reference: 'deliver',
 			    text: gettext('Deliver'),
-- 
2.30.2





^ permalink raw reply	[flat|nested] 4+ messages in thread

* [pmg-devel] applied-series: Re: [PATCH pmg-gui v2 0/2] low-hanging improvments for the quarantine interface
  2022-10-27 19:12 [pmg-devel] [PATCH pmg-gui v2 0/2] low-hanging improvments for the quarantine interface Stoiko Ivanov
  2022-10-27 19:12 ` [pmg-devel] [PATCH pmg-gui v2 1/2] quarantine: refactor spamquarantine controller Stoiko Ivanov
  2022-10-27 19:12 ` [pmg-devel] [PATCH pmg-gui v2 2/2] quarantine: use new controller for virus and attachment quarantines Stoiko Ivanov
@ 2022-10-28  9:35 ` Thomas Lamprecht
  2 siblings, 0 replies; 4+ messages in thread
From: Thomas Lamprecht @ 2022-10-28  9:35 UTC (permalink / raw)
  To: Stoiko Ivanov, pmg-devel

On 27/10/2022 21:12, Stoiko Ivanov wrote:
> v1->v2:
> * dropped already applied patches
> * changed the patches, by splitting the refactoring of the spamquarantine
>   in a patch of its own, and changing virus and attachmentquarantine in
>   the second patch (no functional change intended) - big thanks for the
>   suggestion @Thomas!!
> 
> gave me also the chance to see the adaptations of the icon-colors for delivery
> and delete by Thomas in action - I like it!
> 
> original cover-letter for v1:
> A few bugzilla entries ask for features in the quarantine interface that
> seem quite sensible (e.g. #4137), or are already present in the (by far
> more used) spamquarantine, but never made it to the others.
> 
> This patchset contains a single small fix, and a refactoring of the
> quarantine views to use the same controller.
> 
> Would be grateful for feedback
> 
> 
> Stoiko Ivanov (2):
>   quarantine: refactor spamquarantine controller
>   quarantine: use new controller for virus and attachment quarantines
> 
>  js/AttachmentQuarantine.js            | 113 +++++-----
>  js/Makefile                           |   1 +
>  js/SpamQuarantine.js                  | 290 +++++++++-----------------
>  js/VirusQuarantine.js                 |  86 ++------
>  js/controller/QuarantineController.js | 170 +++++++++++++++
>  5 files changed, 335 insertions(+), 325 deletions(-)
>  create mode 100644 js/controller/QuarantineController.js
> 


applied series, many thanks!




^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2022-10-28  9:36 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-10-27 19:12 [pmg-devel] [PATCH pmg-gui v2 0/2] low-hanging improvments for the quarantine interface Stoiko Ivanov
2022-10-27 19:12 ` [pmg-devel] [PATCH pmg-gui v2 1/2] quarantine: refactor spamquarantine controller Stoiko Ivanov
2022-10-27 19:12 ` [pmg-devel] [PATCH pmg-gui v2 2/2] quarantine: use new controller for virus and attachment quarantines Stoiko Ivanov
2022-10-28  9:35 ` [pmg-devel] applied-series: Re: [PATCH pmg-gui v2 0/2] low-hanging improvments for the quarantine interface Thomas Lamprecht

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal