From 894cd14802b9deba51f0717d41ae5fb85142eee0 Mon Sep 17 00:00:00 2001 From: Yuri Kuznetsov Date: Wed, 19 Jul 2023 14:33:49 +0300 Subject: [PATCH] ref --- .../crm/src/views/record/panels/activities.js | 1071 ++++++++--------- .../crm/src/views/record/panels/history.js | 291 +++-- client/src/views/modal.js | 2 +- client/src/views/record/panels/bottom.js | 3 +- .../src/views/record/panels/relationship.js | 56 +- client/src/views/record/panels/side.js | 3 +- 6 files changed, 714 insertions(+), 712 deletions(-) diff --git a/client/modules/crm/src/views/record/panels/activities.js b/client/modules/crm/src/views/record/panels/activities.js index d1d46831cd..29ac454c10 100644 --- a/client/modules/crm/src/views/record/panels/activities.js +++ b/client/modules/crm/src/views/record/panels/activities.js @@ -26,500 +26,379 @@ * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. ************************************************************************/ -define('crm:views/record/panels/activities', -['views/record/panels/relationship', 'multi-collection'], function (Dep, MultiCollection) { +import RelationshipPanelView from 'views/record/panels/relationship'; +import MultiCollection from 'multi-collection'; - return Dep.extend({ +class ActivitiesPanelView extends RelationshipPanelView { - name: 'activities', + name = 'activities' + orderBy = 'dateStart' + serviceName = 'Activities' + order = 'desc' + rowActionsView = 'crm:views/record/row-actions/activities' + relatedListFiltersDisabled = true + buttonMaxCount = null - orderBy: 'dateStart', + actionList = [ + { + action: 'composeEmail', + label: 'Compose Email', + acl: 'create', + aclScope: 'Email', + }, + ] - serviceName: 'Activities', + listLayout = {} - order: 'desc', + defaultListLayout = { + rows: [ + [ + {name: 'ico', view: 'crm:views/fields/ico'}, + {name: 'name', link: true, view: 'views/event/fields/name-for-history'}, + ], + [ + {name: 'assignedUser'}, + {name: 'dateStart'}, + ], + ] + } - rowActionsView: 'crm:views/record/row-actions/activities', + BUTTON_MAX_COUNT = 3 - relatedListFiltersDisabled: true, + setup() { + this.scopeList = this.getConfig().get(this.name + 'EntityList') || []; - actionList: [ - { + this.buttonMaxCount = this.getConfig().get('activitiesCreateButtonMaxCount'); + + if (typeof this.buttonMaxCount === 'undefined') { + this.buttonMaxCount = this.BUTTON_MAX_COUNT; + } + + this.listLayout = Espo.Utils.cloneDeep(this.listLayout); + + this.defs.create = true; + + this.createAvailabilityHash = {}; + this.entityTypeLinkMap = {}; + this.createEntityTypeStatusMap = {}; + + this.setupActionList(); + this.setupFinalActionList(); + this.setupSorting(); + + this.scopeList.forEach(item => { + if (!(item in this.listLayout)) { + this.listLayout[item] = this.defaultListLayout; + } + }); + + this.url = this.serviceName + '/' + this.model.entityType + '/' + this.model.id + '/' + this.name; + + this.seeds = {}; + + this.wait(true); + + let i = 0; + + this.scopeList.forEach(scope => { + this.getModelFactory().create(scope, seed => { + this.seeds[scope] = seed; + + i++; + + if (i === this.scopeList.length) { + this.wait(false); + } + }); + }); + + if (this.scopeList.length === 0) { + this.wait(false); + } + + this.filterList = []; + + this.scopeList.forEach(item => { + if (!this.getAcl().check(item)) { + return; + } + + if (!this.getAcl().check(item, 'read')) { + return; + } + + if (this.getMetadata().get(['scopes', item, 'disabled'])) { + return; + } + + this.filterList.push(item); + }); + + if (this.filterList.length) { + this.filterList.unshift('all'); + } + + if (this.filterList && this.filterList.length) { + this.filter = this.getStoredFilter(); + } + + this.setupFilterActions(); + + this.setupTitle(); + + this.collection = new MultiCollection(); + this.collection.seeds = this.seeds; + this.collection.url = this.url; + this.collection.orderBy = this.orderBy; + this.collection.order = this.order; + this.collection.maxSize = this.getConfig().get('recordsPerPageSmall') || 5; + + this.setFilter(this.filter); + + this.once('show', () => { + if (!this.isRendered() && !this.isBeingRendered()) { + this.collection.fetch(); + } + }); + } + + translateFilter(name) { + if (name === 'all') { + return this.translate(name, 'presetFilters'); + } + + return this.translate(name, 'scopeNamesPlural'); + } + + isCreateAvailable(scope) { + return this.createAvailabilityHash[scope]; + } + + setupActionList() { + if (this.name === 'activities' && this.buttonMaxCount) { + this.buttonList.push({ action: 'composeEmail', - label: 'Compose Email', + title: 'Compose Email', acl: 'create', aclScope: 'Email', - }, - ], - - listLayout: {}, - - defaultListLayout: { - rows: [ - [ - {name: 'ico', view: 'crm:views/fields/ico'}, - {name: 'name', link: true, view: 'views/event/fields/name-for-history'}, - ], - [ - {name: 'assignedUser'}, - {name: 'dateStart'}, - ], - ] - }, - - buttonMaxCount: null, - - BUTTON_MAX_COUNT: 3, - - setup: function () { - this.scopeList = this.getConfig().get(this.name + 'EntityList') || []; - - this.buttonMaxCount = this.getConfig().get('activitiesCreateButtonMaxCount'); - - if (typeof this.buttonMaxCount === 'undefined') { - this.buttonMaxCount = this.BUTTON_MAX_COUNT; - } - - this.listLayout = Espo.Utils.cloneDeep(this.listLayout); - - this.defs.create = true; - - this.createAvailabilityHash = {}; - this.entityTypeLinkMap = {}; - this.createEntityTypeStatusMap = {}; - - this.setupActionList(); - this.setupFinalActionList(); - this.setupSorting(); - - this.scopeList.forEach(item => { - if (!(item in this.listLayout)) { - this.listLayout[item] = this.defaultListLayout; - } + html: $('') + .addClass(this.getMetadata().get(['clientDefs', 'Email', 'iconClass'])) + .get(0).outerHTML, }); + } - this.url = this.serviceName + '/' + this.model.entityType + '/' + this.model.id + '/' + this.name; - - this.seeds = {}; - - this.wait(true); - - let i = 0; - - this.scopeList.forEach(scope => { - this.getModelFactory().create(scope, seed => { - this.seeds[scope] = seed; - - i++; - - if (i === this.scopeList.length) { - this.wait(false); - } - }); - }); - - if (this.scopeList.length === 0) { - this.wait(false); + this.scopeList.forEach(scope => { + if (!this.getMetadata().get(['clientDefs', scope, 'activityDefs', this.name + 'Create'])) { + return; } - this.filterList = []; - - this.scopeList.forEach(item => { - if (!this.getAcl().check(item)) { - return; - } - - if (!this.getAcl().check(item, 'read')) { - return; - } - - if (this.getMetadata().get(['scopes', item, 'disabled'])) { - return; - } - - this.filterList.push(item); - }); - - if (this.filterList.length) { - this.filterList.unshift('all'); + if (!this.getAcl().checkScope(scope, 'create')) { + return; } - if (this.filterList && this.filterList.length) { - this.filter = this.getStoredFilter(); - } + let label = (this.name === 'history' ? 'Log' : 'Schedule') + ' ' + scope; - this.setupFilterActions(); + let o = { + action: 'createActivity', + text: this.translate(label, 'labels', scope), + data: {}, + acl: 'create', + aclScope: scope, + }; - this.setupTitle(); + let link = this.getMetadata().get(['clientDefs', scope, 'activityDefs', 'link']) - this.collection = new MultiCollection(); - this.collection.seeds = this.seeds; - this.collection.url = this.url; - this.collection.orderBy = this.orderBy; - this.collection.order = this.order; - this.collection.maxSize = this.getConfig().get('recordsPerPageSmall') || 5; + if (link) { + o.data.link = link; - this.setFilter(this.filter); + this.entityTypeLinkMap[scope] = link; - this.once('show', () => { - if (!this.isRendered() && !this.isBeingRendered()) { - this.collection.fetch(); - } - }); - }, - - translateFilter: function (name) { - if (name === 'all') { - return this.translate(name, 'presetFilters'); - } - - return this.translate(name, 'scopeNamesPlural'); - }, - - isCreateAvailable: function (scope) { - return this.createAvailabilityHash[scope]; - }, - - setupActionList: function () { - if (this.name === 'activities' && this.buttonMaxCount) { - this.buttonList.push({ - action: 'composeEmail', - title: 'Compose Email', - acl: 'create', - aclScope: 'Email', - html: $('') - .addClass(this.getMetadata().get(['clientDefs', 'Email', 'iconClass'])) - .get(0).outerHTML, - }); - } - - this.scopeList.forEach(scope => { - if (!this.getMetadata().get(['clientDefs', scope, 'activityDefs', this.name + 'Create'])) { + if (!this.model.hasLink(link)) { return; } - - if (!this.getAcl().checkScope(scope, 'create')) { - return; - } - - let label = (this.name === 'history' ? 'Log' : 'Schedule') + ' ' + scope; - - let o = { - action: 'createActivity', - text: this.translate(label, 'labels', scope), - data: {}, - acl: 'create', - aclScope: scope, - }; - - let link = this.getMetadata().get(['clientDefs', scope, 'activityDefs', 'link']) - - if (link) { - o.data.link = link; - - this.entityTypeLinkMap[scope] = link; - - if (!this.model.hasLink(link)) { - return; - } - } else { - o.data.scope = scope; - - if ( - this.model.entityType !== 'User' && - !this.checkParentTypeAvailability(scope, this.model.entityType) - ) { - return; - } - } - - this.createAvailabilityHash[scope] = true; - - o.data = o.data || {}; - - if (!o.data.status) { - let statusList = this.getMetadata().get(['scopes', scope, this.name + 'StatusList']); - - if (statusList && statusList.length) { - o.data.status = statusList[0]; - } - } - - this.createEntityTypeStatusMap[scope] = o.data.status; - this.actionList.push(o); + } else { + o.data.scope = scope; if ( - this.name === 'activities' && - this.buttonList.length < this.buttonMaxCount + this.model.entityType !== 'User' && + !this.checkParentTypeAvailability(scope, this.model.entityType) ) { - let ob = Espo.Utils.cloneDeep(o); - - let iconClass = this.getMetadata().get(['clientDefs', scope, 'iconClass']); - - if (iconClass) { - ob.title = label; - ob.html = $('').addClass(iconClass).get(0).outerHTML; - - this.buttonList.push(ob); - } - } - }); - }, - - setupFinalActionList: function () { - this.scopeList.forEach((scope, i) => { - if (i === 0 && this.actionList.length) { - this.actionList.push(false); - } - - if (!this.getAcl().checkScope(scope, 'read')) { return; } - - let o = { - action: 'viewRelatedList', - html: $('') - .append( - $('').text(this.translate('View List')), - ' · ', - $('').text(this.translate(scope, 'scopeNamesPlural')), - ) - .get(0).innerHTML, - data: { - scope: scope, - }, - acl: 'read', - aclScope: scope, - }; - - this.actionList.push(o); - }); - }, - - setFilter: function (filter) { - this.filter = filter; - - this.collection.data.entityType = null; - - if (filter && filter !== 'all') { - this.collection.data.entityType = this.filter; } - }, - afterRender: function () { - let afterFetch = () => { - this.createView('list', 'views/record/list-expanded', { - selector: '> .list-container', - pagination: false, - type: 'listRelationship', - rowActionsView: this.rowActionsView, - checkboxes: false, - collection: this.collection, - listLayout: this.listLayout, - }, (view) => { - view.render(); + this.createAvailabilityHash[scope] = true; - this.listenTo(view, 'after:save', () => { - this.fetchActivities(); - this.fetchHistory(); - }); - }); + o.data = o.data || {}; + + if (!o.data.status) { + let statusList = this.getMetadata().get(['scopes', scope, this.name + 'StatusList']); + + if (statusList && statusList.length) { + o.data.status = statusList[0]; + } + } + + this.createEntityTypeStatusMap[scope] = o.data.status; + this.actionList.push(o); + + if ( + this.name === 'activities' && + this.buttonList.length < this.buttonMaxCount + ) { + let ob = Espo.Utils.cloneDeep(o); + + let iconClass = this.getMetadata().get(['clientDefs', scope, 'iconClass']); + + if (iconClass) { + ob.title = label; + ob.html = $('').addClass(iconClass).get(0).outerHTML; + + this.buttonList.push(ob); + } + } + }); + } + + setupFinalActionList() { + this.scopeList.forEach((scope, i) => { + if (i === 0 && this.actionList.length) { + this.actionList.push(false); + } + + if (!this.getAcl().checkScope(scope, 'read')) { + return; + } + + let o = { + action: 'viewRelatedList', + html: $('') + .append( + $('').text(this.translate('View List')), + ' · ', + $('').text(this.translate(scope, 'scopeNamesPlural')), + ) + .get(0).innerHTML, + data: { + scope: scope, + }, + acl: 'read', + aclScope: scope, }; - if (!this.disabled) { + this.actionList.push(o); + }); + } + + setFilter(filter) { + this.filter = filter; + + this.collection.data.entityType = null; + + if (filter && filter !== 'all') { + this.collection.data.entityType = this.filter; + } + } + + afterRender() { + let afterFetch = () => { + this.createView('list', 'views/record/list-expanded', { + selector: '> .list-container', + pagination: false, + type: 'listRelationship', + rowActionsView: this.rowActionsView, + checkboxes: false, + collection: this.collection, + listLayout: this.listLayout, + }, (view) => { + view.render(); + + this.listenTo(view, 'after:save', () => { + this.fetchActivities(); + this.fetchHistory(); + }); + }); + }; + + if (!this.disabled) { + this.collection + .fetch() + .then(() => afterFetch()); + } + else { + this.once('show', () => { this.collection .fetch() - .then(() => afterFetch()); - } - else { - this.once('show', () => { - this.collection - .fetch() - .then(() => afterFetch()) - }); - } - }, - - fetchHistory: function () { - let parentView = this.getParentView(); - - if (parentView) { - if (parentView.hasView('history')) { - let collection = parentView.getView('history').collection; - - if (collection) { - collection.fetch(); - } - } - } - }, - - fetchActivities: function () { - var parentView = this.getParentView(); - - if (parentView) { - if (parentView.hasView('activities')) { - var collection = parentView.getView('activities').collection; - if (collection) { - collection.fetch(); - } - } - } - }, - - fetchActivitiesAndHistory: function () { - - }, - - getCreateActivityAttributes: function (scope, data, callback) { - data = data || {}; - - var attributes = { - status: data.status, - }; - - if (this.model.entityType === 'User') { - if (this.model.isPortal()) { - attributes.usersIds = [this.model.id]; - - var usersIdsNames = {}; - usersIdsNames[this.model.id] = this.model.get('name') - attributes.usersIdsNames = usersIdsNames; - } - else { - attributes.assignedUserId = this.model.id; - attributes.assignedUserName = this.model.get('name'); - } - } - else { - if (this.model.entityType === 'Contact') { - if (this.model.get('accountId') && !this.getConfig().get('b2cMode')) { - attributes.parentType = 'Account'; - attributes.parentId = this.model.get('accountId'); - attributes.parentName = this.model.get('accountName'); - if ( - scope && - !this.getMetadata().get(['entityDefs', scope, 'links', 'contacts']) && - !this.getMetadata().get(['entityDefs', scope, 'links', 'contact']) - ) { - delete attributes.parentType; - delete attributes.parentId; - delete attributes.parentName; - } - } - } - else if (this.model.entityType === 'Lead') { - attributes.parentType = 'Lead'; - attributes.parentId = this.model.id; - attributes.parentName = this.model.get('name'); - } - - if (this.model.entityType !== 'Account' && this.model.has('contactsIds')) { - attributes.contactsIds = this.model.get('contactsIds'); - attributes.contactsNames = this.model.get('contactsNames'); - } - - if (scope) { - if (!attributes.parentId) { - if (this.checkParentTypeAvailability(scope, this.model.entityType)) { - attributes.parentType = this.model.entityType; - attributes.parentId = this.model.id; - attributes.parentName = this.model.get('name'); - } - } - else { - if (attributes.parentType && !this.checkParentTypeAvailability(scope, attributes.parentType)) { - attributes.parentType = null; - attributes.parentId = null; - attributes.parentName = null; - } - } - } - } - - callback.call(this, Espo.Utils.cloneDeep(attributes)); - }, - - checkParentTypeAvailability: function (scope, parentType) { - return ~( - this.getMetadata().get(['entityDefs', scope, 'fields', 'parent', 'entityList']) || [] - ).indexOf(parentType); - }, - - actionCreateRelated: function (data) { - data.link = this.entityTypeLinkMap[data.scope]; - - if (this.createEntityTypeStatusMap[data.scope]) { - data.status = this.createEntityTypeStatusMap[data.scope]; - } - - this.actionCreateActivity(data); - }, - - actionCreateActivity: function (data) { - let link = data.link; - let foreignLink; - let scope; - - if (link) { - scope = this.model.getLinkParam(link, 'entity'); - foreignLink = this.model.getLinkParam(link, 'foreign'); - } - else { - scope = data.scope; - } - - var o = { - scope: scope - }; - - if (link) { - o.relate = { - model: this.model, - link: foreignLink - }; - } - - Espo.Ui.notify(' ... '); - - var viewName = this.getMetadata().get('clientDefs.' + scope + '.modalViews.edit') || - 'views/modals/edit'; - - this.getCreateActivityAttributes(scope, data, attributes => { - o.attributes = attributes; - - this.createView('quickCreate', viewName, o, (view) => { - view.render(); - view.notify(false); - - this.listenToOnce(view, 'after:save', () => { - this.model.trigger('after:relate'); - this.collection.fetch(); - this.fetchHistory(); - }); - }); + .then(() => afterFetch()) }); - }, + } + } - getComposeEmailAttributes: function (scope, data, callback) { - data = data || {}; + fetchHistory() { + let parentView = this.getParentView(); - let attributes = { - status: 'Draft', - to: this.model.get('emailAddress') - }; + if (parentView) { + if (parentView.hasView('history')) { + let collection = parentView.getView('history').collection; - if (this.model.entityType === 'Contact') { - if (this.getConfig().get('b2cMode')) { - attributes.parentType = 'Contact'; - attributes.parentName = this.model.get('name'); - attributes.parentId = this.model.id; + if (collection) { + collection.fetch(); } - else { - if (this.model.get('accountId')) { - attributes.parentType = 'Account'; - attributes.parentId = this.model.get('accountId'); - attributes.parentName = this.model.get('accountName'); + } + } + } + + fetchActivities() { + let parentView = this.getParentView(); + + if (parentView) { + if (parentView.hasView('activities')) { + let collection = parentView.getView('activities').collection; + + if (collection) { + collection.fetch(); + } + } + } + } + + getCreateActivityAttributes(scope, data, callback) { + data = data || {}; + + let attributes = { + status: data.status, + }; + + if (this.model.entityType === 'User') { + let model = /** @type {module:models/user} */this.model; + + if (model.isPortal()) { + attributes.usersIds = [model.id]; + + let usersIdsNames = {}; + usersIdsNames[model.id] = model.get('name') + + attributes.usersIdsNames = usersIdsNames; + } + else { + attributes.assignedUserId = model.id; + attributes.assignedUserName = model.get('name'); + } + } + else { + if (this.model.entityType === 'Contact') { + if (this.model.get('accountId') && !this.getConfig().get('b2cMode')) { + attributes.parentType = 'Account'; + attributes.parentId = this.model.get('accountId'); + attributes.parentName = this.model.get('accountName'); + if ( + scope && + !this.getMetadata().get(['entityDefs', scope, 'links', 'contacts']) && + !this.getMetadata().get(['entityDefs', scope, 'links', 'contact']) + ) { + delete attributes.parentType; + delete attributes.parentId; + delete attributes.parentName; } } } @@ -529,9 +408,9 @@ define('crm:views/record/panels/activities', attributes.parentName = this.model.get('name'); } - if (~['Contact', 'Lead', 'Account'].indexOf(this.model.entityType) && this.model.get('emailAddress')) { - attributes.nameHash = {}; - attributes.nameHash[this.model.get('emailAddress')] = this.model.get('name'); + if (this.model.entityType !== 'Account' && this.model.has('contactsIds')) { + attributes.contactsIds = this.model.get('contactsIds'); + attributes.contactsNames = this.model.get('contactsNames'); } if (scope) { @@ -550,117 +429,231 @@ define('crm:views/record/panels/activities', } } } + } - let emailKeepParentTeamsEntityList = this.getConfig().get('emailKeepParentTeamsEntityList') || []; + callback.call(this, Espo.Utils.cloneDeep(attributes)); + } - if ( - attributes.parentType && - attributes.parentType === this.model.entityType && - ~emailKeepParentTeamsEntityList.indexOf(attributes.parentType) && - this.model.get('teamsIds') && - this.model.get('teamsIds').length - ) { - attributes.teamsIds = Espo.Utils.clone(this.model.get('teamsIds')); - attributes.teamsNames = Espo.Utils.clone(this.model.get('teamsNames') || {}); + checkParentTypeAvailability(scope, parentType) { + return ~( + this.getMetadata().get(['entityDefs', scope, 'fields', 'parent', 'entityList']) || [] + ).indexOf(parentType); + } - let defaultTeamId = this.getUser().get('defaultTeamId'); + // noinspection JSUnusedGlobalSymbols + actionCreateRelated(data) { + data.link = this.entityTypeLinkMap[data.scope]; - if (defaultTeamId && !~attributes.teamsIds.indexOf(defaultTeamId)) { - attributes.teamsIds.push(defaultTeamId); - attributes.teamsNames[defaultTeamId] = this.getUser().get('defaultTeamName'); - } + if (this.createEntityTypeStatusMap[data.scope]) { + data.status = this.createEntityTypeStatusMap[data.scope]; + } - attributes.teamsIds = attributes.teamsIds - .filter(teamId => { - return this.getAcl().checkTeamAssignmentPermission(teamId); - }); - } + this.actionCreateActivity(data); + } - callback.call(this, attributes); - }, + actionCreateActivity(data) { + let link = data.link; + let foreignLink; + let scope; - actionComposeEmail: function (data) { - let self = this; - let link = 'emails'; - let scope = 'Email'; + if (link) { + scope = this.model.getLinkParam(link, 'entity'); + foreignLink = this.model.getLinkParam(link, 'foreign'); + } + else { + scope = data.scope; + } - let relate = null; + let o = { + scope: scope + }; - if ('emails' in this.model.defs['links']) { - relate = { - model: this.model, - link: this.model.defs['links']['emails'].foreign - }; - } + if (link) { + o.relate = { + model: this.model, + link: foreignLink + }; + } - Espo.Ui.notify(' ... '); + Espo.Ui.notify(' ... '); - this.getComposeEmailAttributes(scope, data, attributes => { - this.createView('quickCreate', 'views/modals/compose-email', { - relate: relate, - attributes: attributes, - }, (view) => { - view.render(); - view.notify(false); + let viewName = this.getMetadata().get('clientDefs.' + scope + '.modalViews.edit') || + 'views/modals/edit'; - this.listenToOnce(view, 'after:save', () => { - this.collection.fetch(); - this.model.trigger('after:relate'); - this.fetchHistory(); - }); + this.getCreateActivityAttributes(scope, data, attributes => { + o.attributes = attributes; + + this.createView('quickCreate', viewName, o, (view) => { + view.render(); + view.notify(false); + + this.listenToOnce(view, 'after:save', () => { + this.model.trigger('after:relate'); + this.collection.fetch(); + this.fetchHistory(); }); }); - }, + }); + } - actionRefresh: function () { - this.collection.fetch(); - }, + getComposeEmailAttributes(scope, data, callback) { + let attributes = { + status: 'Draft', + to: this.model.get('emailAddress') + }; - actionSetHeld: function (data) { - let id = data.id; + if (this.model.entityType === 'Contact') { + if (this.getConfig().get('b2cMode')) { + attributes.parentType = 'Contact'; + attributes.parentName = this.model.get('name'); + attributes.parentId = this.model.id; + } + else { + if (this.model.get('accountId')) { + attributes.parentType = 'Account'; + attributes.parentId = this.model.get('accountId'); + attributes.parentName = this.model.get('accountName'); + } + } + } + else if (this.model.entityType === 'Lead') { + attributes.parentType = 'Lead'; + attributes.parentId = this.model.id; + attributes.parentName = this.model.get('name'); + } - if (!id) { - return; + if (~['Contact', 'Lead', 'Account'].indexOf(this.model.entityType) && this.model.get('emailAddress')) { + attributes.nameHash = {}; + attributes.nameHash[this.model.get('emailAddress')] = this.model.get('name'); + } + + if (scope) { + if (!attributes.parentId) { + if (this.checkParentTypeAvailability(scope, this.model.entityType)) { + attributes.parentType = this.model.entityType; + attributes.parentId = this.model.id; + attributes.parentName = this.model.get('name'); + } + } + else { + if (attributes.parentType && !this.checkParentTypeAvailability(scope, attributes.parentType)) { + attributes.parentType = null; + attributes.parentId = null; + attributes.parentName = null; + } + } + } + + let emailKeepParentTeamsEntityList = this.getConfig().get('emailKeepParentTeamsEntityList') || []; + + if ( + attributes.parentType && + attributes.parentType === this.model.entityType && + ~emailKeepParentTeamsEntityList.indexOf(attributes.parentType) && + this.model.get('teamsIds') && + this.model.get('teamsIds').length + ) { + attributes.teamsIds = Espo.Utils.clone(this.model.get('teamsIds')); + attributes.teamsNames = Espo.Utils.clone(this.model.get('teamsNames') || {}); + + let defaultTeamId = this.getUser().get('defaultTeamId'); + + if (defaultTeamId && !~attributes.teamsIds.indexOf(defaultTeamId)) { + attributes.teamsIds.push(defaultTeamId); + attributes.teamsNames[defaultTeamId] = this.getUser().get('defaultTeamName'); } - let model = this.collection.get(id); + attributes.teamsIds = attributes.teamsIds + .filter(teamId => { + return this.getAcl().checkTeamAssignmentPermission(teamId); + }); + } - model.save({status: 'Held'}, {patch: true}) - .then(() => { + callback.call(this, attributes); + } + + // noinspection JSUnusedGlobalSymbols + actionComposeEmail(data) { + let scope = 'Email'; + + let relate = null; + + if ('emails' in this.model.defs['links']) { + relate = { + model: this.model, + link: this.model.defs['links']['emails'].foreign + }; + } + + Espo.Ui.notify(' ... '); + + this.getComposeEmailAttributes(scope, data, attributes => { + this.createView('quickCreate', 'views/modals/compose-email', { + relate: relate, + attributes: attributes, + }, (view) => { + view.render(); + view.notify(false); + + this.listenToOnce(view, 'after:save', () => { this.collection.fetch(); + this.model.trigger('after:relate'); this.fetchHistory(); }); - }, + }); + }); + } - actionSetNotHeld: function (data) { - let id = data.id; + actionRefresh() { + this.collection.fetch(); + } - if (!id) { - return; - } + actionSetHeld(data) { + let id = data.id; - let model = this.collection.get(id); + if (!id) { + return; + } - model.save({status: 'Not Held'}, {patch: true}) - .then(() => { - this.collection.fetch(); - this.fetchHistory(); - }); - }, + let model = this.collection.get(id); - actionViewRelatedList: function (data) { - data.url = 'Activities/' + this.model.entityType + '/' + - this.model.id + '/' + this.name + '/list/' + data.scope; + model.save({status: 'Held'}, {patch: true}) + .then(() => { + this.collection.fetch(); + this.fetchHistory(); + }); + } - data.title = this.translate(this.defs.label) + - ' @right ' + this.translate(data.scope, 'scopeNamesPlural'); + actionSetNotHeld(data) { + let id = data.id; - data.viewOptions = data.viewOptions || {}; - data.viewOptions.massUnlinkDisabled = true; - data.viewOptions.fullFormUrl = '#' + this.model.entityType + '/' + this.name + '/' + - this.model.id + '/' + data.scope; + if (!id) { + return; + } - Dep.prototype.actionViewRelatedList.call(this, data); - }, - }); -}); + let model = this.collection.get(id); + + model.save({status: 'Not Held'}, {patch: true}) + .then(() => { + this.collection.fetch(); + this.fetchHistory(); + }); + } + + actionViewRelatedList(data) { + data.url = 'Activities/' + this.model.entityType + '/' + + this.model.id + '/' + this.name + '/list/' + data.scope; + + data.title = this.translate(this.defs.label) + + ' @right ' + this.translate(data.scope, 'scopeNamesPlural'); + + data.viewOptions = data.viewOptions || {}; + data.viewOptions.massUnlinkDisabled = true; + data.viewOptions.fullFormUrl = '#' + this.model.entityType + '/' + this.name + '/' + + this.model.id + '/' + data.scope; + + super.actionViewRelatedList(data); + } +} + +export default ActivitiesPanelView; diff --git a/client/modules/crm/src/views/record/panels/history.js b/client/modules/crm/src/views/record/panels/history.js index 4e316fd2d8..ebeb889689 100644 --- a/client/modules/crm/src/views/record/panels/history.js +++ b/client/modules/crm/src/views/record/panels/history.js @@ -26,183 +26,182 @@ * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. ************************************************************************/ -define('crm:views/record/panels/history', ['crm:views/record/panels/activities'], function (Dep) { +import ActivitiesPanelView from 'crm:views/record/panels/activities'; +import EmailHelper from 'email-helper'; - return Dep.extend({ +class HistoryPanelView extends ActivitiesPanelView { - name: 'history', + name = 'history' + orderBy = 'dateStart' + orderDirection = 'desc' + rowActionsView = 'crm:views/record/row-actions/history' - orderBy: 'dateStart', + actionList = [] - orderDirection: 'desc', - - rowActionsView: 'crm:views/record/row-actions/history', - - actionList: [], - - listLayout: { - 'Email': { - rows: [ - [ - {name: 'ico', view: 'crm:views/fields/ico'}, - { - name: 'name', - link: true, - }, - ], - [ - {name: 'status'}, - {name: 'dateSent'}, - {name: 'hasAttachment', view: 'views/email/fields/has-attachment'}, - ], - ] - }, + listLayout = { + 'Email': { + rows: [ + [ + {name: 'ico', view: 'crm:views/fields/ico'}, + { + name: 'name', + link: true, + }, + ], + [ + {name: 'status'}, + {name: 'dateSent'}, + {name: 'hasAttachment', view: 'views/email/fields/has-attachment'}, + ], + ] }, + } - where: { - scope: false, - }, + where = { + scope: false, + } - setupActionList: function () { - Dep.prototype.setupActionList.call(this); + setupActionList() { + super.setupActionList(); - this.actionList.push({ - action: 'archiveEmail', - label: 'Archive Email', - acl: 'create', - aclScope: 'Email', - }); - }, + this.actionList.push({ + action: 'archiveEmail', + label: 'Archive Email', + acl: 'create', + aclScope: 'Email', + }); + } - getArchiveEmailAttributes: function (scope, data, callback) { - data = data || {}; + getArchiveEmailAttributes(scope, data, callback) { + let attributes = { + dateSent: this.getDateTime().getNow(15), + status: 'Archived', + from: this.model.get('emailAddress'), + to: this.getUser().get('emailAddress'), + }; - let attributes = { - dateSent: this.getDateTime().getNow(15), - status: 'Archived', - from: this.model.get('emailAddress'), - to: this.getUser().get('emailAddress'), - }; - - if (this.model.entityType === 'Contact') { - if (this.getConfig().get('b2cMode')) { - attributes.parentType = 'Contact'; - attributes.parentName = this.model.get('name'); - attributes.parentId = this.model.id; - } else { - if (this.model.get('accountId')) { - attributes.parentType = 'Account', - attributes.parentId = this.model.get('accountId'); - attributes.parentName = this.model.get('accountName'); - } - } - } else if (this.model.entityType === 'Lead') { - attributes.parentType = 'Lead'; - attributes.parentId = this.model.id + if (this.model.entityType === 'Contact') { + if (this.getConfig().get('b2cMode')) { + attributes.parentType = 'Contact'; attributes.parentName = this.model.get('name'); - } - - attributes.nameHash = {}; - attributes.nameHash[this.model.get('emailAddress')] = this.model.get('name'); - - if (scope) { - if (!attributes.parentId) { - if (this.checkParentTypeAvailability(scope, this.model.entityType)) { - attributes.parentType = this.model.entityType; - attributes.parentId = this.model.id; - attributes.parentName = this.model.get('name'); - } - } else { - if (attributes.parentType && !this.checkParentTypeAvailability(scope, attributes.parentType)) { - attributes.parentType = null; - attributes.parentId = null; - attributes.parentName = null; - } + attributes.parentId = this.model.id; + } else { + if (this.model.get('accountId')) { + attributes.parentType = 'Account'; + attributes.parentId = this.model.get('accountId'); + attributes.parentName = this.model.get('accountName'); } } + } else if (this.model.entityType === 'Lead') { + attributes.parentType = 'Lead'; + attributes.parentId = this.model.id + attributes.parentName = this.model.get('name'); + } - callback.call(this, attributes); - }, + attributes.nameHash = {}; + attributes.nameHash[this.model.get('emailAddress')] = this.model.get('name'); - actionArchiveEmail: function (data) { - let self = this; - let link = 'emails'; - let scope = 'Email'; - - let relate = null; - - if ('emails' in this.model.defs['links']) { - relate = { - model: this.model, - link: this.model.defs['links']['emails'].foreign, - }; + if (scope) { + if (!attributes.parentId) { + if (this.checkParentTypeAvailability(scope, this.model.entityType)) { + attributes.parentType = this.model.entityType; + attributes.parentId = this.model.id; + attributes.parentName = this.model.get('name'); + } + } else { + if (attributes.parentType && !this.checkParentTypeAvailability(scope, attributes.parentType)) { + attributes.parentType = null; + attributes.parentId = null; + attributes.parentName = null; + } } + } - Espo.Ui.notify(' ... '); + callback.call(this, attributes); + } - let viewName = this.getMetadata().get('clientDefs.' + scope + '.modalViews.edit') || - 'views/modals/edit'; + // noinspection JSUnusedGlobalSymbols + actionArchiveEmail(data) { + let scope = 'Email'; - this.getArchiveEmailAttributes(scope, data, (attributes) => { - this.createView('quickCreate', viewName, { - scope: scope, - relate: relate, - attributes: attributes, - }, (view) => { - view.render(); - view.notify(false); + let relate = null; - this.listenToOnce(view, 'after:save', () => { - this.collection.fetch(); - this.model.trigger('after:relate'); - }); + if ('emails' in this.model.defs['links']) { + relate = { + model: this.model, + link: this.model.defs['links']['emails'].foreign, + }; + } + + Espo.Ui.notify(' ... '); + + let viewName = this.getMetadata().get('clientDefs.' + scope + '.modalViews.edit') || + 'views/modals/edit'; + + this.getArchiveEmailAttributes(scope, data, attributes => { + this.createView('quickCreate', viewName, { + scope: scope, + relate: relate, + attributes: attributes, + }, (view) => { + view.render(); + view.notify(false); + + this.listenToOnce(view, 'after:save', () => { + this.collection.fetch(); + this.model.trigger('after:relate'); }); }); - }, + }); + } - actionReply: function (data) { - let id = data.id; + // noinspection JSUnusedGlobalSymbols + actionReply(data) { + let id = data.id; - if (!id) { - return; - } + if (!id) { + return; + } - Espo.loader.require('email-helper', EmailHelper => { - let emailHelper = - new EmailHelper(this.getLanguage(), this.getUser(), this.getDateTime(), this.getAcl()); + let emailHelper = new EmailHelper( + this.getLanguage(), + this.getUser(), + this.getDateTime(), + this.getAcl() + ); - Espo.Ui.notify(' ... '); + Espo.Ui.notify(' ... '); - this.getModelFactory().create('Email') - .then(model => { - model.id = id; + this.getModelFactory().create('Email') + .then(model => { + model.id = id; - model.fetch() - .then(() => { - let attributes = emailHelper - .getReplyAttributes(model, data, - this.getPreferences().get('emailReplyToAllByDefault')); + model.fetch() + .then(() => { + let attributes = emailHelper + .getReplyAttributes(model, data, + this.getPreferences().get('emailReplyToAllByDefault')); - let viewName = this.getMetadata().get('clientDefs.Email.modalViews.compose') || - 'views/modals/compose-email'; + let viewName = this.getMetadata().get('clientDefs.Email.modalViews.compose') || + 'views/modals/compose-email'; - return this.createView('quickCreate', viewName, { - attributes: attributes, - focusForCreate: true, - }); - }) - .then(view => { - view.render(); + return this.createView('quickCreate', viewName, { + attributes: attributes, + focusForCreate: true, + }); + }) + .then(view => { + view.render(); - this.listenToOnce(view, 'after:save', () => { - this.collection.fetch(); - this.model.trigger('after:relate'); - }); + this.listenToOnce(view, 'after:save', () => { + this.collection.fetch(); + this.model.trigger('after:relate'); + }); - view.notify(false); - }); + Espo.Ui.notify(false); }); }); - }, - }); -}); + } +} + +export default HistoryPanelView; diff --git a/client/src/views/modal.js b/client/src/views/modal.js index 6325e4d5e3..d1eed7279e 100644 --- a/client/src/views/modal.js +++ b/client/src/views/modal.js @@ -171,7 +171,7 @@ class ModalView extends View { * Dropdown action items. * * @protected - * @type {module:views/modal~Button[]|false} + * @type {Array} */ dropdownItemList = [] diff --git a/client/src/views/record/panels/bottom.js b/client/src/views/record/panels/bottom.js index 0f21a8f315..8df7b3794f 100644 --- a/client/src/views/record/panels/bottom.js +++ b/client/src/views/record/panels/bottom.js @@ -47,7 +47,7 @@ class BottomPanelView extends View { /** * @protected - * @type {module:views/record/panels-container~action[]} + * @type {Array} */ actionList = null @@ -342,6 +342,7 @@ class BottomPanelView extends View { this.createView(viewKey, viewName, o); } + // noinspection JSUnusedGlobalSymbols /** * Is tab-hidden. * diff --git a/client/src/views/record/panels/relationship.js b/client/src/views/record/panels/relationship.js index 99c9d06a3d..e16fd9f3c5 100644 --- a/client/src/views/record/panels/relationship.js +++ b/client/src/views/record/panels/relationship.js @@ -195,7 +195,8 @@ class RelationshipPanelView extends BottomPanelView { this.setupActions(); - var layoutName = 'listSmall'; + let layoutName = 'listSmall'; + this.setupListLayout(); if (this.listLayoutName) { @@ -311,7 +312,7 @@ class RelationshipPanelView extends BottomPanelView { setupTitle() { this.title = this.title || this.translate(this.link, 'links', this.model.entityType); - var iconHtml = ''; + let iconHtml = ''; if (!this.getConfig().get('scopeColorsDisabled')) { iconHtml = this.getHelper().getScopeColorIconHtml(this.scope); @@ -336,10 +337,10 @@ class RelationshipPanelView extends BottomPanelView { * @protected */ setupSorting() { - var orderBy = this.defs.orderBy || this.defs.sortBy || this.orderBy; - var order = this.defs.orderDirection || this.orderDirection || this.order; + let orderBy = this.defs.orderBy || this.defs.sortBy || this.orderBy; + let order = this.defs.orderDirection || this.orderDirection || this.order; - if ('asc' in this.defs) { // TODO remove in 5.8 + if ('asc' in this.defs) { // @todo Remove. order = this.defs.asc ? 'asc' : 'desc'; } @@ -424,10 +425,10 @@ class RelationshipPanelView extends BottomPanelView { } /** - * @private + * @protected */ getStoredFilter() { - var key = 'panelFilter' + this.model.entityType + '-' + (this.panelName || this.name); + let key = 'panelFilter' + this.model.entityType + '-' + (this.panelName || this.name); return this.getStorage().get('state', key) || null; } @@ -436,7 +437,7 @@ class RelationshipPanelView extends BottomPanelView { * @private */ storeFilter(filter) { - var key = 'panelFilter' + this.model.entityType + '-' + (this.panelName || this.name); + let key = 'panelFilter' + this.model.entityType + '-' + (this.panelName || this.name); if (filter) { this.getStorage().set('state', key, filter); @@ -459,14 +460,15 @@ class RelationshipPanelView extends BottomPanelView { } } + // noinspection JSUnusedGlobalSymbols /** * A `select-filter` action. * * @protected */ actionSelectFilter(data) { - var filter = data.name; - var filterInternal = filter; + let filter = data.name; + let filterInternal = filter; if (filter === 'all') { filterInternal = false; @@ -476,7 +478,7 @@ class RelationshipPanelView extends BottomPanelView { this.setFilter(filterInternal); this.filterList.forEach(item => { - var $el = this.$el.closest('.panel').find('[data-name="'+item+'"] span'); + let $el = this.$el.closest('.panel').find('[data-name="'+item+'"] span'); if (item === filter) { $el.removeClass('hidden'); @@ -487,10 +489,10 @@ class RelationshipPanelView extends BottomPanelView { this.collection.reset(); - var listView = this.getView('list'); + let listView = this.getView('list'); if (listView && listView.$el) { - var height = listView.$el.parent().get(0).clientHeight; + let height = listView.$el.parent().get(0).clientHeight; listView.$el.empty(); @@ -527,7 +529,7 @@ class RelationshipPanelView extends BottomPanelView { * @protected */ actionViewRelatedList(data) { - var viewName = + let viewName = this.getMetadata().get( ['clientDefs', this.model.entityType, 'relationshipPanels', this.name, 'viewModalView'] ) || @@ -535,15 +537,15 @@ class RelationshipPanelView extends BottomPanelView { this.viewModalView || 'views/modals/related-list'; - var scope = data.scope || this.scope; + let scope = data.scope || this.scope; - var filter = this.filter; + let filter = this.filter; if (this.relatedListFiltersDisabled) { filter = null; } - var options = { + let options = { model: this.model, panelName: this.panelName, link: this.link, @@ -565,7 +567,7 @@ class RelationshipPanelView extends BottomPanelView { }; if (data.viewOptions) { - for (var item in data.viewOptions) { + for (let item in data.viewOptions) { options[item] = data.viewOptions[item]; } } @@ -578,7 +580,7 @@ class RelationshipPanelView extends BottomPanelView { view.render(); this.listenTo(view, 'action', (action, data, e) => { - var method = 'action' + Espo.Utils.upperCaseFirst(action); + let method = 'action' + Espo.Utils.upperCaseFirst(action); if (typeof this[method] === 'function') { this[method](data, e); @@ -604,6 +606,7 @@ class RelationshipPanelView extends BottomPanelView { return !!this.defs.create; } + // noinspection JSUnusedLocalSymbols /** * Is select available. * @@ -615,6 +618,7 @@ class RelationshipPanelView extends BottomPanelView { return !!this.defs.select; } + // noinspection JSUnusedGlobalSymbols /** * A `view-related` action. * @@ -645,16 +649,17 @@ class RelationshipPanelView extends BottomPanelView { }); } + // noinspection JSUnusedGlobalSymbols /** * An `edit-related` action. * * @protected */ actionEditRelated(data) { - var id = data.id; - var scope = this.collection.get(id).name; + let id = data.id; + let scope = this.collection.get(id).name; - var viewName = this.getMetadata().get('clientDefs.' + scope + '.modalViews.edit') || + let viewName = this.getMetadata().get('clientDefs.' + scope + '.modalViews.edit') || 'views/modals/edit'; Espo.Ui.notify(' ... '); @@ -675,13 +680,14 @@ class RelationshipPanelView extends BottomPanelView { }); } + // noinspection JSUnusedGlobalSymbols /** * An `unlink-related` action. * * @protected */ actionUnlinkRelated(data) { - var id = data.id; + let id = data.id; this.confirm({ message: this.translate('unlinkRecordConfirmation', 'messages'), @@ -702,13 +708,14 @@ class RelationshipPanelView extends BottomPanelView { }); } + // noinspection JSUnusedGlobalSymbols /** * A `remove-related` action. * * @protected */ actionRemoveRelated(data) { - var id = data.id; + let id = data.id; this.confirm({ message: this.translate('removeRecordConfirmation', 'messages'), @@ -731,6 +738,7 @@ class RelationshipPanelView extends BottomPanelView { }); } + // noinspection JSUnusedGlobalSymbols /** * An `unlink-all-related` action. * diff --git a/client/src/views/record/panels/side.js b/client/src/views/record/panels/side.js index f62a3aa2ab..b0807c4f34 100644 --- a/client/src/views/record/panels/side.js +++ b/client/src/views/record/panels/side.js @@ -74,7 +74,7 @@ class SidePanelView extends View { /** * @protected - * @type {module:views/record/panels-container~button[]} + * @type {Array} */ buttonList = null @@ -159,6 +159,7 @@ class SidePanelView extends View { } item = Espo.Utils.clone(item); + item.viewKey = item.name + 'Field'; item.label = item.label || item.name;