diff --git a/application/Espo/Entities/Note.php b/application/Espo/Entities/Note.php index 65c0e340ae..a257009aba 100644 --- a/application/Espo/Entities/Note.php +++ b/application/Espo/Entities/Note.php @@ -211,4 +211,50 @@ class Note extends Entity return in_array($userId, $userIdList); } + + public function loadAdditionalFields(): void + { + if ( + $this->getType() == self::TYPE_POST || + $this->getType() == self::TYPE_EMAIL_RECEIVED + ) { + $this->loadAttachments(); + } + + if ($this->getParentId() && $this->getParentType()) { + $this->loadParentNameField('parent'); + } + + if ($this->getRelatedId() && $this->getRelatedType()) { + $this->loadParentNameField('related'); + } + + if ( + $this->getType() == self::TYPE_POST && + $this->getParentId() === null && + !$this->get('isGlobal') + ) { + $targetType = $this->getTargetType(); + + if ( + !$targetType || + $targetType === self::TARGET_USERS || + $targetType === self::TARGET_SELF + ) { + $this->loadLinkMultipleField('users'); + } + + if ( + $targetType !== self::TARGET_USERS && + $targetType !== self::TARGET_SELF + ) { + if (!$targetType || $targetType === self::TARGET_TEAMS) { + $this->loadLinkMultipleField('teams'); + } + else if ($targetType === self::TARGET_PORTALS) { + $this->loadLinkMultipleField('portals'); + } + } + } + } } diff --git a/application/Espo/Resources/i18n/en_US/Global.json b/application/Espo/Resources/i18n/en_US/Global.json index 068765bcc2..d5ef6ae825 100644 --- a/application/Espo/Resources/i18n/en_US/Global.json +++ b/application/Espo/Resources/i18n/en_US/Global.json @@ -1,5 +1,6 @@ { "scopeNames": { + "Note": "Note", "Email": "Email", "User": "User", "Team": "Team", @@ -57,6 +58,7 @@ "Mass Action": "Mass Action" }, "scopeNamesPlural": { + "Note": "Notes", "Email": "Emails", "User": "Users", "Team": "Teams", diff --git a/application/Espo/Resources/metadata/clientDefs/Note.json b/application/Espo/Resources/metadata/clientDefs/Note.json index 02c82ebc4c..e66d2d047d 100644 --- a/application/Espo/Resources/metadata/clientDefs/Note.json +++ b/application/Espo/Resources/metadata/clientDefs/Note.json @@ -1,4 +1,5 @@ { + "controller": "controllers/note", "collection": "collections/note", "recordViews": { "edit": "views/note/record/edit", diff --git a/application/Espo/Services/Note.php b/application/Espo/Services/Note.php index 6a3d16e95d..6b0f1bdaab 100644 --- a/application/Espo/Services/Note.php +++ b/application/Espo/Services/Note.php @@ -383,6 +383,17 @@ class Note extends Record parent::unlink($id, $link, $foreignId); } + /** + * @param NoteEntity $entity + * @return void + */ + public function loadAdditionalFields(Entity $entity) + { + parent::loadAdditionalFields($entity); + + $entity->loadAdditionalFields(); + } + private function getUserRepository(): UserRepository { /** @var UserRepository */ diff --git a/application/Espo/Services/Stream.php b/application/Espo/Services/Stream.php index ca8b0463f5..a8d9ce33a2 100644 --- a/application/Espo/Services/Stream.php +++ b/application/Espo/Services/Stream.php @@ -955,50 +955,9 @@ class Stream return $whereClause; } - private function loadNoteAdditionalFields(NoteEntity $e): void + private function loadNoteAdditionalFields(NoteEntity $note): void { - if ( - $e->getType() == NoteEntity::TYPE_POST || - $e->getType() == NoteEntity::TYPE_EMAIL_RECEIVED - ) { - $e->loadAttachments(); - } - - if ($e->getParentId() && $e->getParentType()) { - $e->loadParentNameField('parent'); - } - - if ($e->getRelatedId() && $e->getRelatedType()) { - $e->loadParentNameField('related'); - } - - if ( - $e->getType() == NoteEntity::TYPE_POST && - $e->getParentId() === null && - !$e->get('isGlobal') - ) { - $targetType = $e->getTargetType(); - - if ( - !$targetType || - $targetType === NoteEntity::TARGET_USERS || - $targetType === NoteEntity::TARGET_SELF - ) { - $e->loadLinkMultipleField('users'); - } - - if ( - $targetType !== NoteEntity::TARGET_USERS && - $targetType !== NoteEntity::TARGET_SELF - ) { - if (!$targetType || $targetType === NoteEntity::TARGET_TEAMS) { - $e->loadLinkMultipleField('teams'); - } - else if ($targetType === NoteEntity::TARGET_PORTALS) { - $e->loadLinkMultipleField('portals'); - } - } - } + $note->loadAdditionalFields(); } /** diff --git a/client/res/templates/stream/notes/assign.tpl b/client/res/templates/stream/notes/assign.tpl index 9d9b7b37b4..d21ef5cbfb 100644 --- a/client/res/templates/stream/notes/assign.tpl +++ b/client/res/templates/stream/notes/assign.tpl @@ -13,5 +13,5 @@
- {{{createdAt}}} + {{{createdAt}}}
diff --git a/client/res/templates/stream/notes/create-related.tpl b/client/res/templates/stream/notes/create-related.tpl index 6d83f22317..2457e76ba1 100644 --- a/client/res/templates/stream/notes/create-related.tpl +++ b/client/res/templates/stream/notes/create-related.tpl @@ -15,5 +15,5 @@
- {{{createdAt}}} + {{{createdAt}}}
diff --git a/client/res/templates/stream/notes/create.tpl b/client/res/templates/stream/notes/create.tpl index 552cee3eee..8237703e9c 100644 --- a/client/res/templates/stream/notes/create.tpl +++ b/client/res/templates/stream/notes/create.tpl @@ -15,5 +15,5 @@
- {{{createdAt}}} + {{{createdAt}}}
diff --git a/client/res/templates/stream/notes/email-received.tpl b/client/res/templates/stream/notes/email-received.tpl index a0311014b3..b4ace4a0be 100644 --- a/client/res/templates/stream/notes/email-received.tpl +++ b/client/res/templates/stream/notes/email-received.tpl @@ -41,6 +41,6 @@ {{/if}}
- {{{createdAt}}} + {{{createdAt}}}
diff --git a/client/res/templates/stream/notes/email-sent.tpl b/client/res/templates/stream/notes/email-sent.tpl index 4ac77ac3c0..58445b778b 100644 --- a/client/res/templates/stream/notes/email-sent.tpl +++ b/client/res/templates/stream/notes/email-sent.tpl @@ -41,6 +41,6 @@ {{/if}}
- {{{createdAt}}} + {{{createdAt}}}
diff --git a/client/res/templates/stream/notes/post.tpl b/client/res/templates/stream/notes/post.tpl index 99ff44dbba..4a88ee5e3a 100644 --- a/client/res/templates/stream/notes/post.tpl +++ b/client/res/templates/stream/notes/post.tpl @@ -32,5 +32,5 @@ {{/if}}
- {{{createdAt}}} + {{{createdAt}}}
diff --git a/client/res/templates/stream/notes/status.tpl b/client/res/templates/stream/notes/status.tpl index bd5e6a3f89..8962c829a1 100644 --- a/client/res/templates/stream/notes/status.tpl +++ b/client/res/templates/stream/notes/status.tpl @@ -15,5 +15,5 @@
- {{{createdAt}}} + {{{createdAt}}}
diff --git a/client/res/templates/stream/notes/update.tpl b/client/res/templates/stream/notes/update.tpl index 707fdaa430..983bde0384 100644 --- a/client/res/templates/stream/notes/update.tpl +++ b/client/res/templates/stream/notes/update.tpl @@ -46,5 +46,5 @@
- {{{createdAt}}} + {{{createdAt}}}
diff --git a/client/src/controllers/note.js b/client/src/controllers/note.js new file mode 100644 index 0000000000..a46a15515a --- /dev/null +++ b/client/src/controllers/note.js @@ -0,0 +1,67 @@ +/************************************************************************ + * This file is part of EspoCRM. + * + * EspoCRM - Open Source CRM application. + * Copyright (C) 2014-2022 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko + * Website: https://www.espocrm.com + * + * EspoCRM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * EspoCRM 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with EspoCRM. If not, see http://www.gnu.org/licenses/. + * + * 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 General Public License version 3. + * + * In accordance with Section 7(b) of the GNU General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. + ************************************************************************/ + +define('controllers/note', ['controller'], function (Dep) { + + /** + * @class + * @name Class + * @extends module:controller.Class + * @memberOf module:controllers/note + */ + return Dep.extend(/** @lends module:controllers/note.Class# */{ + + actionView: function (options) { + let id = options.id; + + if (!id) { + throw new Espo.Espo.Exceptions.NotFound; + } + + let viewName = 'views/note/detail' || + this.getMetadata().get(['clientDefs', this.name, 'views', 'detail']); + + let model; + + this.showLoadingNotification(); + + this.modelFactory.create('Note') + .then(m => { + model = m; + model.id = id; + + return model.fetch(); + }) + .then(() => { + this.hideLoadingNotification(); + + this.main(viewName, {model: model}); + }); + }, + }); +}); diff --git a/client/src/views/note/detail.js b/client/src/views/note/detail.js new file mode 100644 index 0000000000..d39f73a421 --- /dev/null +++ b/client/src/views/note/detail.js @@ -0,0 +1,120 @@ +/************************************************************************ + * This file is part of EspoCRM. + * + * EspoCRM - Open Source CRM application. + * Copyright (C) 2014-2022 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko + * Website: https://www.espocrm.com + * + * EspoCRM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * EspoCRM 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with EspoCRM. If not, see http://www.gnu.org/licenses/. + * + * 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 General Public License version 3. + * + * In accordance with Section 7(b) of the GNU General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. + ************************************************************************/ + +define('views/note/detail', ['views/main'], (Dep) => { + + /** + * @class + * @name Class + * @extends module:views/main.Class + * @memberOf module:views/note/detail + */ + return Dep.extend(/** @lends module:views/note/detail.Class# */{ + + templateContent: ` + +
{{{record}}}
+ `, + + /** + * @private + */ + isDeleted: false, + + setup: function () { + this.scope = this.model.entityType; + + this.setupHeader(); + this.setupRecord(); + + this.listenToOnce(this.model, 'remove', () => { + this.clearView('record'); + this.isDeleted = true; + this.getHeaderView().reRender(); + }); + }, + + setupHeader: function () { + this.createView('header', 'views/header', { + selector: '> .header', + scope: this.scope, + fontSizeFlexible: true, + }); + }, + + setupRecord: function () { + this.wait( + this.getCollectionFactory().create(this.scope) + .then(collection => { + this.collection = collection; + this.collection.add(this.model); + + this.createView('record', 'views/stream/record/list', { + selector: '> .record', + collection: this.collection, + isUserStream: true, + }); + }) + ); + }, + + getHeader: function () { + let parentType = this.model.get('parentType'); + let parentId = this.model.get('parentId'); + let parentName = this.model.get('parentName'); + let type = this.model.get('type'); + + let $type = $('') + .text(this.getLanguage().translateOption(type, 'type', 'Note')); + + if (this.model.get('deleted') || this.isDeleted) { + $type.css('text-decoration', 'line-through'); + } + + if (parentType && parentId) { + return this.buildHeaderHtml([ + $('') + .attr('href', '#' + parentType) + .text(this.translate(parentType, 'scopeNamesPlural')), + $('') + .attr('href', '#' + parentType + '/view/' + parentId) + .text(parentName || parentId), + $('') + .text(this.translate('Stream', 'scopeNames')), + $type, + ]); + } + + return this.buildHeaderHtml([ + $('') + .text(this.translate('Stream', 'scopeNames')), + $type, + ]); + }, + }); +}); diff --git a/client/src/views/stream/notes/post.js b/client/src/views/stream/notes/post.js index 3dfb30f474..cb06e1279c 100644 --- a/client/src/views/stream/notes/post.js +++ b/client/src/views/stream/notes/post.js @@ -153,6 +153,8 @@ define('views/stream/notes/post', ['views/stream/note'], function (Dep) { if (!this.model.has('usersIds') || !this.model.get('usersIds').length) { this.createMessage(); + + return; } let userIdList = this.model.get('usersIds');