calendar websocket
This commit is contained in:
@@ -29,6 +29,8 @@
|
||||
|
||||
namespace Espo\Core\Templates\Entities;
|
||||
|
||||
use Espo\Core\Field\Link;
|
||||
use Espo\Core\Name\Field;
|
||||
use Espo\Core\ORM\Entity;
|
||||
|
||||
class Event extends Entity
|
||||
@@ -48,4 +50,13 @@ class Event extends Entity
|
||||
{
|
||||
return $this->set('status', $status);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 9.2.0
|
||||
*/
|
||||
public function getAssignedUser(): ?Link
|
||||
{
|
||||
/** @var ?Link */
|
||||
return $this->getValueObject(Field::ASSIGNED_USER);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* 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 <https://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 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.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Modules\Crm\Hooks\Call;
|
||||
|
||||
use Espo\Core\Hook\Hook\AfterRemove;
|
||||
use Espo\Core\Hook\Hook\AfterSave;
|
||||
use Espo\Core\WebSocket\Submission;
|
||||
use Espo\Modules\Crm\Entities\Call;
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\ORM\Repository\Option\RemoveOptions;
|
||||
use Espo\ORM\Repository\Option\SaveOptions;
|
||||
|
||||
/**
|
||||
* @implements AfterSave<Call>
|
||||
* @implements AfterRemove<Call>
|
||||
*/
|
||||
class CalendarWebSocket implements AfterSave, AfterRemove
|
||||
{
|
||||
public function __construct(
|
||||
private Submission $submission,
|
||||
) {}
|
||||
|
||||
public function afterSave(Entity $entity, SaveOptions $options): void
|
||||
{
|
||||
$this->process($entity);
|
||||
}
|
||||
|
||||
public function afterRemove(Entity $entity, RemoveOptions $options): void
|
||||
{
|
||||
$this->process($entity);
|
||||
}
|
||||
|
||||
private function process(Call $entity): void
|
||||
{
|
||||
foreach ($entity->getUsers()->getIdList() as $userId) {
|
||||
$this->submission->submit('calendarUpdate', $userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* 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 <https://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 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.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Modules\Crm\Hooks\Common;
|
||||
|
||||
use Espo\Core\Hook\Hook\AfterRemove;
|
||||
use Espo\Core\Hook\Hook\AfterSave;
|
||||
use Espo\Core\Name\Field;
|
||||
use Espo\Core\Templates\Entities\Event;
|
||||
use Espo\Core\WebSocket\Submission;
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\ORM\Repository\Option\RemoveOptions;
|
||||
use Espo\ORM\Repository\Option\SaveOptions;
|
||||
|
||||
/**
|
||||
* @implements AfterSave<Entity>
|
||||
* @implements AfterRemove<Entity>
|
||||
*/
|
||||
class CalendarWebSocket implements AfterSave, AfterRemove
|
||||
{
|
||||
public function __construct(
|
||||
private Submission $submission,
|
||||
) {}
|
||||
|
||||
public function afterSave(Entity $entity, SaveOptions $options): void
|
||||
{
|
||||
if (!$entity instanceof Event) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->process($entity);
|
||||
}
|
||||
|
||||
public function afterRemove(Entity $entity, RemoveOptions $options): void
|
||||
{
|
||||
if (!$entity instanceof Event) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->process($entity);
|
||||
}
|
||||
|
||||
private function process(Event $entity): void
|
||||
{
|
||||
if ($entity->hasLinkMultipleField(Field::ASSIGNED_USERS)) {
|
||||
foreach ($entity->getLinkMultipleIdList(Field::ASSIGNED_USER) as $userId) {
|
||||
$this->submission->submit('calendarUpdate', $userId);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($entity->getAssignedUser()) {
|
||||
$this->submission->submit('calendarUpdate', $entity->getAssignedUser()->getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* 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 <https://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 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.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Modules\Crm\Hooks\Meeting;
|
||||
|
||||
use Espo\Core\Hook\Hook\AfterRemove;
|
||||
use Espo\Core\Hook\Hook\AfterSave;
|
||||
use Espo\Core\WebSocket\Submission;
|
||||
use Espo\Modules\Crm\Entities\Meeting;
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\ORM\Repository\Option\RemoveOptions;
|
||||
use Espo\ORM\Repository\Option\SaveOptions;
|
||||
|
||||
/**
|
||||
* @implements AfterSave<Meeting>
|
||||
* @implements AfterRemove<Meeting>
|
||||
*/
|
||||
class CalendarWebSocket implements AfterSave, AfterRemove
|
||||
{
|
||||
public function __construct(
|
||||
private Submission $submission,
|
||||
) {}
|
||||
|
||||
public function afterSave(Entity $entity, SaveOptions $options): void
|
||||
{
|
||||
$this->process($entity);
|
||||
}
|
||||
|
||||
public function afterRemove(Entity $entity, RemoveOptions $options): void
|
||||
{
|
||||
$this->process($entity);
|
||||
}
|
||||
|
||||
private function process(Meeting $entity): void
|
||||
{
|
||||
foreach ($entity->getUsers()->getIdList() as $userId) {
|
||||
$this->submission->submit('calendarUpdate', $userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* 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 <https://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 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.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Modules\Crm\Hooks\Task;
|
||||
|
||||
use Espo\Core\Hook\Hook\AfterRemove;
|
||||
use Espo\Core\Hook\Hook\AfterSave;
|
||||
use Espo\Core\Name\Field;
|
||||
use Espo\Core\WebSocket\Submission;
|
||||
use Espo\Modules\Crm\Entities\Task;
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\ORM\Repository\Option\RemoveOptions;
|
||||
use Espo\ORM\Repository\Option\SaveOptions;
|
||||
|
||||
/**
|
||||
* @implements AfterSave<Task>
|
||||
* @implements AfterRemove<Task>
|
||||
*/
|
||||
class CalendarWebSocket implements AfterSave, AfterRemove
|
||||
{
|
||||
public function __construct(
|
||||
private Submission $submission,
|
||||
) {}
|
||||
|
||||
public function afterSave(Entity $entity, SaveOptions $options): void
|
||||
{
|
||||
$this->process($entity);
|
||||
}
|
||||
|
||||
public function afterRemove(Entity $entity, RemoveOptions $options): void
|
||||
{
|
||||
$this->process($entity);
|
||||
}
|
||||
|
||||
private function process(Task $entity): void
|
||||
{
|
||||
if ($entity->hasLinkMultipleField(Field::ASSIGNED_USERS)) {
|
||||
foreach ($entity->getLinkMultipleIdList(Field::ASSIGNED_USER) as $userId) {
|
||||
$this->submission->submit('calendarUpdate', $userId);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($entity->getAssignedUser()) {
|
||||
$this->submission->submit('calendarUpdate', $entity->getAssignedUser()->getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
{
|
||||
"categories": {
|
||||
"popupNotifications.event": {}
|
||||
"popupNotifications.event": {},
|
||||
"calendarUpdate": {
|
||||
"accessCheckCommand": "AclCheck --userId=:userId --scope=Calendar"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,12 +30,13 @@ import View from 'view';
|
||||
import CalendarEditViewModal from 'crm:views/calendar/modals/edit-view';
|
||||
import {inject} from 'di';
|
||||
import {ShortcutManager} from 'helpers/site/shortcut-manager';
|
||||
import DebounceHelper from 'helpers/util/debounce';
|
||||
|
||||
class CalendarPage extends View {
|
||||
|
||||
template = 'crm:calendar/calendar-page'
|
||||
|
||||
el = '#main'
|
||||
//el = '#main'
|
||||
|
||||
fullCalendarModeList = [
|
||||
'month',
|
||||
@@ -64,6 +65,18 @@ class CalendarPage extends View {
|
||||
@inject(ShortcutManager)
|
||||
shortcutManager
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {DebounceHelper}
|
||||
*/
|
||||
webSocketDebounceHelper
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
webSocketDebounceInterval = 500
|
||||
|
||||
/**
|
||||
* A shortcut-key => action map.
|
||||
*
|
||||
@@ -149,6 +162,20 @@ class CalendarPage extends View {
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{
|
||||
* userId?: string,
|
||||
* userName?: string|null,
|
||||
* mode?: string|null,
|
||||
* date?: string|null,
|
||||
* }} options
|
||||
*/
|
||||
constructor(options) {
|
||||
super(options);
|
||||
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
setup() {
|
||||
this.mode = this.mode || this.options.mode || null;
|
||||
this.date = this.date || this.options.date || null;
|
||||
@@ -179,16 +206,52 @@ class CalendarPage extends View {
|
||||
|
||||
this.shortcutManager.add(this, this.shortcutKeys);
|
||||
|
||||
this.once('remove', () => {
|
||||
this.on('remove', () => {
|
||||
this.shortcutManager.remove(this);
|
||||
});
|
||||
|
||||
if (!this.mode || ~this.fullCalendarModeList.indexOf(this.mode) || this.mode.indexOf('view-') === 0) {
|
||||
this.setupCalendar();
|
||||
}
|
||||
else if (this.mode === 'timeline') {
|
||||
} else if (this.mode === 'timeline') {
|
||||
this.setupTimeline();
|
||||
}
|
||||
this.initWebSocket();
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
initWebSocket() {
|
||||
if (this.options.userId && this.getUser().id !== this.options.userId) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.webSocketDebounceHelper = new DebounceHelper({
|
||||
interval: this.webSocketDebounceInterval,
|
||||
handler: () => this.handleWebSocketUpdate(),
|
||||
});
|
||||
|
||||
if (!this.getHelper().webSocketManager) {
|
||||
const testHandler = () => this.webSocketDebounceHelper.process();
|
||||
|
||||
this.on('remove', () => window.removeEventListener('calendar-update', testHandler));
|
||||
|
||||
// For testing purpose.
|
||||
window.addEventListener('calendar-update', testHandler);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.getHelper().webSocketManager.subscribe('calendarUpdate', () => this.webSocketDebounceHelper.process());
|
||||
|
||||
this.on('remove', () => this.getHelper().webSocketManager.unsubscribe('calendarUpdate'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
handleWebSocketUpdate() {
|
||||
this.getCalendarView()?.actionRefresh({suppressLoadingAlert: true});
|
||||
}
|
||||
|
||||
afterRender() {
|
||||
|
||||
Reference in New Issue
Block a user