diff --git a/client/src/helpers/misc/attachment-insert-from-source.js b/client/src/helpers/misc/attachment-insert-from-source.js new file mode 100644 index 0000000000..5d12d14391 --- /dev/null +++ b/client/src/helpers/misc/attachment-insert-from-source.js @@ -0,0 +1,161 @@ +/************************************************************************ + * This file is part of EspoCRM. + * + * EspoCRM – Open Source CRM application. + * Copyright (C) 2014-2025 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko + * Website: https://www.espocrm.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. + ************************************************************************/ + +import {inject} from 'di'; +import Metadata from 'metadata'; +import ModelFactory from 'model-factory'; + +/** + * @internal + */ +export default class AttachmentInsertSourceFromHelper { + + /** + * @param {import('views/fields/attachment-multiple').default|import('views/fields/file').default} view + */ + constructor(view) { + /** @private */ + this.view = view; + + /** @private */ + this.model = view.model; + } + + /** + * @type {Metadata} + * @private + */ + @inject(Metadata) + metadata + + /** + * @type {ModelFactory} + * @private + */ + @inject(ModelFactory) + modelFactory + + + /** + * @param {{ + * source: string, + * onInsert: function(import('model').default[]), + * }} params + */ + insert(params) { + const source = params.source; + + const viewName = + this.metadata.get(['clientDefs', 'Attachment', 'sourceDefs', source, 'insertModalView']) || + this.metadata.get(['clientDefs', source, 'modalViews', 'select']) || + 'views/modals/select-records'; + + let filters = {}; + + if (('getSelectFilters' + source) in this.view) { + filters = this.view['getSelectFilters' + source]() || {}; + } + + if (this.model.attributes.parentId && this.model.attributes.parentType === 'Account') { + if ( + this.metadata.get(`entityDefs.${source}.fields.account.type`) === 'link' && + this.metadata.get(`entityDefs.${source}.links.account.entity`) === 'Account' + ) { + filters = { + account: { + type: 'equals', + attribute: 'accountId', + value: this.model.attributes.parentId, + data: { + type: 'is', + idValue: this.model.attributes.parentId, + nameValue: this.model.attributes.parentType, + }, + }, + ...filters, + }; + } + } + + let boolFilterList = this.metadata.get(`clientDefs.Attachment.sourceDefs.${source}.boolFilterList`); + + if (('getSelectBoolFilterList' + source) in this.view) { + boolFilterList = this.view['getSelectBoolFilterList' + source](); + } + + let primaryFilterName = this.metadata.get(`clientDefs.Attachment.sourceDefs.${source}.primaryFilter`); + + if (('getSelectPrimaryFilterName' + source) in this.view) { + primaryFilterName = this.view['getSelectPrimaryFilterName' + source](); + } + + /** @type {module:views/modals/select-records~Options} */ + const options = { + entityType: source, + createButton: false, + filters: filters, + boolFilterList: boolFilterList, + primaryFilterName: primaryFilterName, + multiple: true, + onSelect: models => { + models.forEach(async model => { + if (model.entityType === 'Attachment') { + params.onInsert([model]); + + return; + } + + /** @type {Record[]} */ + const attachmentDataList = await Espo.Ajax.postRequest(`${source}/action/getAttachmentList`, { + id: model.id, + field: this.view.name, + parentType: this.view.entityType, + }); + + const attachmentSeed = await this.modelFactory.create('Attachment'); + + for (const item of attachmentDataList) { + const attachment = attachmentSeed.clone(); + + attachment.set(item); + + params.onInsert([attachment]); + } + }); + }, + }; + + Espo.Ui.notifyWait(); + + this.view.createView('modal', viewName, options, view => { + view.render(); + + Espo.Ui.notify(); + }); + } +} diff --git a/client/src/views/fields/attachment-multiple.js b/client/src/views/fields/attachment-multiple.js index 793ae57fe9..047996b95d 100644 --- a/client/src/views/fields/attachment-multiple.js +++ b/client/src/views/fields/attachment-multiple.js @@ -30,6 +30,7 @@ import BaseFieldView from 'views/fields/base'; import FileUpload from 'helpers/file-upload'; +import AttachmentInsertSourceFromHelper from 'helpers/misc/attachment-insert-from-source'; /** * An attachment-multiple field. @@ -411,10 +412,9 @@ class AttachmentMultipleFieldView extends BaseFieldView { /** * @protected * @param {import('model').default} attachment - * @param {string|null} [link] * @param {boolean} [ui] */ - pushAttachment(attachment, link, ui) { + pushAttachment(attachment, ui) { const arr = _.clone(this.model.get(this.idsName) || []); arr.push(attachment.id); @@ -662,7 +662,7 @@ class AttachmentMultipleFieldView extends BaseFieldView { return; } - this.pushAttachment(attachment, null, true); + this.pushAttachment(attachment, true); $attachmentBox.attr('data-id', attachment.id); $attachmentBox.trigger('ready'); @@ -887,94 +887,19 @@ class AttachmentMultipleFieldView extends BaseFieldView { } } + /** + * @private + * @param {string} source + */ insertFromSource(source) { - const viewName = - this.getMetadata().get(['clientDefs', 'Attachment', 'sourceDefs', source, 'insertModalView']) || - this.getMetadata().get(['clientDefs', source, 'modalViews', 'select']) || - 'views/modals/select-records'; + const helper = new AttachmentInsertSourceFromHelper(this); - if (viewName) { - Espo.Ui.notifyWait(); - - let filters = null; - - if (('getSelectFilters' + source) in this) { - filters = this['getSelectFilters' + source](); - - if (this.model.get('parentId') && this.model.get('parentType') === 'Account') { - if ( - this.getMetadata() - .get(['entityDefs', source, 'fields', 'account', 'type']) === 'link' - ) { - filters = { - account: { - type: 'equals', - field: 'accountId', - value: this.model.get('parentId'), - valueName: this.model.get('parentName') - } - }; - } - } - } - - let boolFilterList = this.getMetadata() - .get(['clientDefs', 'Attachment', 'sourceDefs', source, 'boolFilterList']); - - if (('getSelectBoolFilterList' + source) in this) { - boolFilterList = this['getSelectBoolFilterList' + source](); - } - - let primaryFilterName = this.getMetadata() - .get(['clientDefs', 'Attachment', 'sourceDefs', source, 'primaryFilter']); - - if (('getSelectPrimaryFilterName' + source) in this) { - primaryFilterName = this['getSelectPrimaryFilterName' + source](); - } - - this.createView('insertFromSource', viewName, { - scope: source, - createButton: false, - filters: filters, - boolFilterList: boolFilterList, - primaryFilterName: primaryFilterName, - multiple: true, - }, view => { - view.render(); - - Espo.Ui.notify(false); - - this.listenToOnce(view, 'select', (modelList) =>{ - if (Object.prototype.toString.call(modelList) !== '[object Array]') { - modelList = [modelList]; - } - - modelList.forEach(model => { - if (model.entityType === 'Attachment') { - this.pushAttachment(model); - - return; - } - - Espo.Ajax - .postRequest(source + '/action/getAttachmentList', { - id: model.id, - field: this.name, - parentType: this.entityType, - }) - .then(attachmentList => { - attachmentList.forEach(item => { - this.getModelFactory().create('Attachment', attachment => { - attachment.set(item); - - this.pushAttachment(attachment, true); - }); - }); - }); - }); - }); - }); - } + helper.insert({ + source: source, + onInsert: models => { + models.forEach(model => this.pushAttachment(model)); + }, + }); } validateRequired() { diff --git a/client/src/views/fields/file.js b/client/src/views/fields/file.js index 4c09b2ed75..0fac10441f 100644 --- a/client/src/views/fields/file.js +++ b/client/src/views/fields/file.js @@ -30,6 +30,7 @@ import LinkFieldView from 'views/fields/link'; import FileUpload from 'helpers/file-upload'; +import AttachmentInsertSourceFromHelper from 'helpers/misc/attachment-insert-from-source'; /** * A file field. @@ -750,96 +751,19 @@ class FileFieldView extends LinkFieldView { return $att; } + /** + * @private + * @param {string} source + */ insertFromSource(source) { - const viewName = - this.getMetadata().get(['clientDefs', 'Attachment', 'sourceDefs', source, 'insertModalView']) || - this.getMetadata().get(['clientDefs', source, 'modalViews', 'select']) || - 'views/modals/select-records'; + const helper = new AttachmentInsertSourceFromHelper(this); - if (viewName) { - Espo.Ui.notifyWait(); - - let filters = null; - - if (('getSelectFilters' + source) in this) { - filters = this['getSelectFilters' + source](); - - if (this.model.get('parentId') && this.model.get('parentType') === 'Account') { - if ( - this.getMetadata() - .get(['entityDefs', source, 'fields', 'account', 'type']) === 'link' - ) { - filters = { - account: { - type: 'equals', - field: 'accountId', - value: this.model.get('parentId'), - valueName: this.model.get('parentName'), - } - }; - } - } - } - - let boolFilterList = this.getMetadata().get( - ['clientDefs', 'Attachment', 'sourceDefs', source, 'boolFilterList'] - ); - - if (('getSelectBoolFilterList' + source) in this) { - boolFilterList = this['getSelectBoolFilterList' + source](); - } - - let primaryFilterName = this.getMetadata().get( - ['clientDefs', 'Attachment', 'sourceDefs', source, 'primaryFilter'] - ); - - if (('getSelectPrimaryFilterName' + source) in this) { - primaryFilterName = this['getSelectPrimaryFilterName' + source](); - } - - this.createView('insertFromSource', viewName, { - scope: source, - createButton: false, - filters: filters, - boolFilterList: boolFilterList, - primaryFilterName: primaryFilterName, - multiple: false, - }, (view) => { - view.render(); - - Espo.Ui.notify(false); - - this.listenToOnce(view, 'select', (modelList) => { - if (Object.prototype.toString.call(modelList) !== '[object Array]') { - modelList = [modelList]; - } - - modelList.forEach(model => { - if (model.entityType === 'Attachment') { - this.setAttachment(model); - - return; - } - - Espo.Ajax - .postRequest(source + '/action/getAttachmentList', { - id: model.id, - field: this.name, - relatedType: this.entityType, - }) - .then(attachmentList => { - attachmentList.forEach(item => { - this.getModelFactory().create('Attachment', (attachment) => { - attachment.set(item); - - this.setAttachment(attachment); - }); - }); - }); - }); - }); - }); - } + helper.insert({ + source: source, + onInsert: models => { + models.forEach(model => this.setAttachment(model)); + }, + }); } fetch() {