diff --git a/client/res/templates/email-folder/list-side.tpl b/client/res/templates/email-folder/list-side.tpl
index 975e809ea4..3abeefd830 100644
--- a/client/res/templates/email-folder/list-side.tpl
+++ b/client/res/templates/email-folder/list-side.tpl
@@ -1,5 +1,4 @@
-
-
+
\ No newline at end of file
+
diff --git a/client/src/views/email/list.js b/client/src/views/email/list.js
index 2556d6af81..bbf72fd6be 100644
--- a/client/src/views/email/list.js
+++ b/client/src/views/email/list.js
@@ -26,9 +26,15 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
-define('views/email/list', 'views/list', function (Dep) {
+define('views/email/list', ['views/list'], function (Dep) {
- return Dep.extend({
+ /**
+ * @class
+ * @name Class
+ * @memberOf module:views/email/list
+ * @extends module:views/list.Class
+ */
+ return Dep.extend(/** @lends module:views/email/list.Class# */{
createButton: false,
@@ -44,6 +50,78 @@ define('views/email/list', 'views/list', function (Dep) {
keepCurrentRootUrl: true,
+ /** @const */
+ FOLDER_ALL: 'all',
+ /** @const */
+ FOLDER_INBOX: 'inbox',
+ /** @const */
+ FOLDER_IMPORTANT: 'important',
+ /** @const */
+ FOLDER_SENT: 'sent',
+ /** @const */
+ FOLDER_DRAFTS: 'drafts',
+ /** @const */
+ FOLDER_TRASH: 'trash',
+
+ noDropFolderIdList: [
+ 'all',
+ 'sent',
+ 'drafts',
+ ],
+
+ events: {
+ 'mousedown .folders-container + .list-container a.link': function (e) {
+ $(e.target).attr('draggable', 'true');
+ },
+ 'dragstart a.link': function (e) {
+ let $target = $(e.target);
+ let id = $target.attr('data-id');
+
+ e.originalEvent.dataTransfer.dropEffect = 'move';
+ e.originalEvent.dataTransfer.effectAllowed = 'move';
+
+ e.originalEvent.dataTransfer.setData('text/plain', id);
+ },
+ 'dragenter .folder-list > li.droppable': function (e) {
+ if (this.selectedFolderId === this.FOLDER_ALL) {
+ return;
+ }
+
+ let $target = $(e.target);
+
+ $target.addClass('active');
+ $target.find('a').css('pointer-events', 'none');
+ },
+ 'dragleave .folder-list > li.droppable': function (e) {
+ if (this.selectedFolderId === this.FOLDER_ALL) {
+ return;
+ }
+
+ let $target = $(e.target);
+
+ $target.removeClass('active')
+ $target.find('a').css('pointer-events', '');
+ },
+ 'drop .folder-list > li.droppable': function (e) {
+ if (this.selectedFolderId === this.FOLDER_ALL) {
+ return;
+ }
+
+ let $target = $(e.target);
+ let folderId = $target.attr('data-id');
+ let id = e.originalEvent.dataTransfer.getData('text/plain');
+
+ $target.removeClass('active');
+ $target.find('a').css('pointer-events', '');
+
+ this.onDrop(id, folderId);
+ },
+ 'dragover .folder-list > li.droppable': function (e) {
+ e.preventDefault();
+ },
+ ...Dep.prototype.events,
+ },
+
setup: function () {
Dep.prototype.setup.call(this);
@@ -140,7 +218,13 @@ define('views/email/list', 'views/list', function (Dep) {
loadFolders: function () {
var xhr = null;
- this.getFolderCollection((collection) => {
+ this.getFolderCollection(collection => {
+ collection.forEach(model => {
+ if (this.noDropFolderIdList.indexOf(model.id) === -1) {
+ model.droppable = true;
+ }
+ });
+
this.createView('folders', 'views/email-folder/list-side', {
collection: collection,
emailCollection: this.collection,
@@ -216,6 +300,46 @@ define('views/email/list', 'views/list', function (Dep) {
}
},
+ onDrop: function (id, folderId) {
+ if (folderId === this.FOLDER_IMPORTANT) {
+ this.getRecordView().actionMarkAsImportant({id: id});
+
+ return;
+ }
+
+ if (this.selectedFolderId === this.FOLDER_TRASH) {
+ if (folderId === this.FOLDER_TRASH) {
+ return;
+ }
+
+ if (folderId === this.FOLDER_INBOX) {
+ this.getRecordView().actionRetrieveFromTrash({id: id});
+
+ return;
+ }
+
+ this.getRecordView().actionRetrieveFromTrashMoveToFolder({id: id, folderId: folderId});
+
+ return;
+ }
+
+ if (folderId === this.FOLDER_TRASH) {
+ this.getRecordView().actionMoveToTrash({id: id});
+
+ return;
+ }
+
+ this.getRecordView().actionMoveToFolder({id: id, folderId: folderId});
+ },
+
+ /**
+ * @protected
+ * @return {module:views/email/record/list.Class}
+ */
+ getRecordView: function () {
+ return this.getView('list');
+ },
+
/**
* @protected
* @param {JQueryKeyEventObject} e
diff --git a/client/src/views/email/record/list.js b/client/src/views/email/record/list.js
index ed5fb64ed2..ea7f96b6af 100644
--- a/client/src/views/email/record/list.js
+++ b/client/src/views/email/record/list.js
@@ -28,7 +28,13 @@
define('views/email/record/list', ['views/record/list', 'helpers/mass-action'], function (Dep, MassActionHelper) {
- return Dep.extend({
+ /**
+ * @class
+ * @name Class
+ * @memberOf module:views/email/record/list
+ * @extends module:views/record/list.Class
+ */
+ return Dep.extend(/** @lends module:views/email/record/list.Class# */{
rowActionsView: 'views/email/record/row-actions/default',
@@ -309,7 +315,9 @@ define('views/email/record/list', ['views/record/list', 'helpers/mass-action'],
},
actionMoveToTrash: function (data) {
- var id = data.id;
+ let id = data.id;
+
+ Espo.Ui.notify(' ... ');
Espo.Ajax
.postRequest('Email/action/moveToTrash', {
@@ -323,12 +331,11 @@ define('views/email/record/list', ['views/record/list', 'helpers/mass-action'],
},
actionRetrieveFromTrash: function (data) {
- var id = data.id;
+ let id = data.id;
- Espo.Ajax
- .postRequest('Email/action/retrieveFromTrash', {
- id: id
- })
+ Espo.Ui.notify(' ... ');
+
+ this.retrieveFromTrash(id)
.then(() => {
Espo.Ui.warning(this.translate('Retrieved from Trash', 'labels', 'Email'));
@@ -336,8 +343,60 @@ define('views/email/record/list', ['views/record/list', 'helpers/mass-action'],
});
},
+ /**
+ * @param {string} id
+ * @return {Promise}
+ */
+ retrieveFromTrash: function (id) {
+ return Espo.Ajax.postRequest('Email/action/retrieveFromTrash', {id: id});
+ },
+
+ actionRetrieveFromTrashMoveToFolder: function (data) {
+ let id = data.id;
+ let folderId = data.folderId;
+
+ Espo.Ui.notify(' ... ');
+
+ this.retrieveFromTrash(id)
+ .then(() => {
+ return this.moveToFolder(id, folderId)
+ })
+ .then(() => {
+ this.collection.fetch().then(() => {
+ Espo.Ui.success(this.translate('Done'));
+ });
+ });
+ },
+
+ /**
+ * @param {string} id
+ * @param {string} folderId
+ * @return {Promise}
+ */
+ moveToFolder: function (id, folderId) {
+ return Espo.Ajax
+ .postRequest('Email/action/moveToFolder', {
+ id: id,
+ folderId: folderId,
+ });
+ },
+
actionMoveToFolder: function (data) {
- var id = data.id;
+ let id = data.id;
+ let folderId = data.folderId;
+
+ if (folderId) {
+ Espo.Ui.notify(' ... ');
+
+ this.moveToFolder(id, folderId)
+ .then(() => {
+ this.collection.fetch().then(() => {
+ Espo.Ui.success(this.translate('Done'));
+ });
+ });
+
+ return;
+ }
this.createView('dialog', 'views/email-folder/modals/select-folder', {}, view => {
view.render();
@@ -345,11 +404,9 @@ define('views/email/record/list', ['views/record/list', 'helpers/mass-action'],
this.listenToOnce(view, 'select', folderId => {
this.clearView('dialog');
- Espo.Ajax
- .postRequest('Email/action/moveToFolder', {
- id: id,
- folderId: folderId
- })
+ Espo.Ui.notify(' ... ');
+
+ this.moveToFolder(id, folderId)
.then(() => {
this.collection.fetch().then(() => {
Espo.Ui.success(this.translate('Done'));
diff --git a/frontend/less/espo/custom.less b/frontend/less/espo/custom.less
index e3f2b11a3c..a5fd794967 100644
--- a/frontend/less/espo/custom.less
+++ b/frontend/less/espo/custom.less
@@ -984,6 +984,19 @@ input.global-search-input {
}
}
+.list-group {
+ .list-group-item {
+ &.droppable.active {
+ background-color: var(--state-warning-bg);
+ }
+ }
+}
+
+.list-group-side {
+ > li.droppable.active {
+ border-left-color: var(--brand-warning);
+ }
+}
.list-group-item {
margin-bottom: 0;