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 @@
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 @@
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 @@
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}}
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}}
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}}
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 @@
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 @@
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');