snapshot of https://github.com/espocrm/espocrm.git (master, 2026-09-18; blobs > 131072B omitted)
Some checks failed
Test / Test on PHP 8.3 (push) Failing after 5s
Test / Test on PHP 8.4 (push) Failing after 4s
Test / Test on PHP 8.5 (push) Failing after 3s
TypeScript static analysis / TypeScript check (push) Failing after 14s
Test Integration on MySQL / Test on PHP 8.3 (push) Failing after 1s
Test Integration on MySQL / Test on PHP 8.5 (push) Failing after 1s
Test Integration on PostgreSQL / Test on PHP 8.4 fix (push) Failing after 1s
Test Integration on PostgreSQL / Test on PHP 8.4 master (push) Failing after 1s
Some checks failed
Test / Test on PHP 8.3 (push) Failing after 5s
Test / Test on PHP 8.4 (push) Failing after 4s
Test / Test on PHP 8.5 (push) Failing after 3s
TypeScript static analysis / TypeScript check (push) Failing after 14s
Test Integration on MySQL / Test on PHP 8.3 (push) Failing after 1s
Test Integration on MySQL / Test on PHP 8.5 (push) Failing after 1s
Test Integration on PostgreSQL / Test on PHP 8.4 fix (push) Failing after 1s
Test Integration on PostgreSQL / Test on PHP 8.4 master (push) Failing after 1s
This commit is contained in:
1299
client/modules/crm/css/vis.css
Normal file
1299
client/modules/crm/css/vis.css
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
||||
<div class="calendar-container no-window-scroll">
|
||||
{{{calendar}}}
|
||||
</div>
|
||||
32
client/modules/crm/res/templates/calendar/calendar.tpl
Normal file
32
client/modules/crm/res/templates/calendar/calendar.tpl
Normal file
@@ -0,0 +1,32 @@
|
||||
{{#if header}}
|
||||
<div class="row button-container">
|
||||
<div class="col-sm-4 col-xs-5">
|
||||
<div class="btn-group range-switch-group">
|
||||
<button class="btn btn-text btn-icon" data-action="prev"><span class="fas fa-chevron-left"></span></button>
|
||||
<button class="btn btn-text btn-icon" data-action="next"><span class="fas fa-chevron-right"></span></button>
|
||||
</div>
|
||||
<div class="btn-group range-switch-group">
|
||||
<button class="btn btn-text strong" data-action="today" title="{{todayLabel}}">
|
||||
<span class="hidden-sm hidden-xs">{{todayLabel}}</span><span class="visible-sm visible-xs">{{todayLabelShort}}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="btn btn-text{{#unless isCustomView}} hidden{{/unless}} btn-icon"
|
||||
data-action="editCustomView"
|
||||
title="{{translate 'Edit'}}"
|
||||
><span class="fas fa-pencil-alt fa-sm"></span></button>
|
||||
</div>
|
||||
|
||||
<div class="date-title col-sm-4 col-xs-7">
|
||||
<h4><span style="cursor: pointer;" data-action="refresh" title="{{translate 'Refresh'}}"></span></h4></div>
|
||||
|
||||
<div class="col-sm-4 col-xs-12">
|
||||
<div class="btn-group pull-right mode-buttons">
|
||||
{{{modeButtons}}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div class="calendar"></div>
|
||||
20
client/modules/crm/res/templates/calendar/modals/edit.tpl
Normal file
20
client/modules/crm/res/templates/calendar/modals/edit.tpl
Normal file
@@ -0,0 +1,20 @@
|
||||
{{#if isNew}}
|
||||
<div class="scope-switcher radio-container">
|
||||
{{#each scopeList}}
|
||||
<div>
|
||||
<label class="radio-label">
|
||||
<input
|
||||
type="radio"
|
||||
name="scope"
|
||||
class="form-radio"
|
||||
{{#ifEqual this ../scope}} checked{{/ifEqual}}
|
||||
value="{{./this}}"
|
||||
>
|
||||
{{translate this category='scopeNames'}}
|
||||
</label>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div class="edit-container record no-side-margin">{{{edit}}}</div>
|
||||
53
client/modules/crm/res/templates/calendar/mode-buttons.tpl
Normal file
53
client/modules/crm/res/templates/calendar/mode-buttons.tpl
Normal file
@@ -0,0 +1,53 @@
|
||||
{{#each visibleModeDataList}}
|
||||
<button class="btn btn-text strong{{#ifEqual mode ../mode}} active{{/ifEqual}}" data-action="mode" data-mode="{{mode}}" title="{{label}}"><span class="hidden-md hidden-sm hidden-xs">{{label}}</span><span class="visible-md visible-sm visible-xs">{{labelShort}}</span></button>
|
||||
{{/each}}
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-text dropdown-toggle" data-toggle="dropdown"><span class="fas fa-ellipsis-h"></span></button>
|
||||
<ul class="dropdown-menu pull-right">
|
||||
{{#each hiddenModeDataList}}
|
||||
<li>
|
||||
<a
|
||||
role="button"
|
||||
tabindex="0"
|
||||
class="{{#ifEqual mode ../mode}} active{{/ifEqual}}"
|
||||
data-action="mode"
|
||||
data-mode="{{mode}}"
|
||||
>{{label}}</a>
|
||||
</li>
|
||||
{{/each}}
|
||||
{{#if hiddenModeDataList.length}}
|
||||
<li class="divider"></li>
|
||||
{{/if}}
|
||||
{{#each scopeFilterDataList}}
|
||||
<li>
|
||||
<a
|
||||
role="button"
|
||||
tabindex="0"
|
||||
data-action="toggleScopeFilter"
|
||||
data-name="{{scope}}"
|
||||
>
|
||||
<span class="fas fa-check filter-check-icon check-icon pull-right{{#if disabled}} hidden{{/if}}"></span>
|
||||
<div>{{translate scope category='scopeNamesPlural'}}</div>
|
||||
|
||||
</a>
|
||||
</li>
|
||||
{{/each}}
|
||||
{{#if hasMoreItems}}
|
||||
<li class="divider"></li>
|
||||
{{/if}}
|
||||
{{#if isCustomViewAvailable}}
|
||||
<li>
|
||||
<a
|
||||
role="button"
|
||||
tabindex="0"
|
||||
data-action="createCustomView"
|
||||
>{{translate 'Create Shared View' scope='Calendar'}}</a>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{#if hasWorkingTimeCalendarLink}}
|
||||
<li>
|
||||
<a href="#WorkingTimeCalendar">{{translate 'WorkingTimeCalendar' category='scopeNamesPlural'}}</a>
|
||||
</li>
|
||||
{{/if}}
|
||||
</ul>
|
||||
</div>
|
||||
55
client/modules/crm/res/templates/calendar/timeline.tpl
Normal file
55
client/modules/crm/res/templates/calendar/timeline.tpl
Normal file
@@ -0,0 +1,55 @@
|
||||
<link href="{{basePath}}client/modules/crm/css/vis.css" rel="stylesheet">
|
||||
|
||||
{{#if header}}
|
||||
<div class="row button-container">
|
||||
<div class="col-sm-4 col-xs-12">
|
||||
<div class="btn-group">
|
||||
<button
|
||||
class="btn btn-text btn-icon"
|
||||
title="{{translate 'Refresh'}}"
|
||||
data-action="refresh"
|
||||
><span class="fas fa-sync-alt"></span></button>
|
||||
<button
|
||||
class="btn btn-text"
|
||||
data-action="today"
|
||||
>{{translate 'Today' scope='Calendar'}}</button>
|
||||
</div>{{#if calendarTypeSelectEnabled}}<div class="btn-group calendar-type-button-group">
|
||||
<div class="btn-group " role="group">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-text dropdown-toggle"
|
||||
data-toggle="dropdown"
|
||||
><span class="calendar-type-label">{{calendarTypeLabel}}</span> <span class="caret"></span></button>
|
||||
<ul class="dropdown-menu">
|
||||
{{#each calendarTypeDataList}}
|
||||
<li>
|
||||
<a role="button" tabindex="0" data-action="toggleCalendarType" data-name="{{type}}">
|
||||
<span
|
||||
class="fas fa-check calendar-type-check-icon pull-right{{#if disabled}} hidden{{/if}}"
|
||||
></span> {{label}}
|
||||
</a>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</div>
|
||||
<button
|
||||
class="btn btn-text{{#ifNotEqual calendarType 'shared'}} hidden{{/ifNotEqual}} btn-icon"
|
||||
data-action="showSharedCalendarOptions"
|
||||
title="{{translate 'Shared Mode Options' scope='Calendar'}}"
|
||||
><span class="fas fa-pencil-alt fa-sm"></span></button>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div class="date-title col-sm-4 hidden-xs">
|
||||
<h4><span style="cursor: pointer;" data-action="refresh" title="{{translate 'Refresh'}}"></span></h4></div>
|
||||
|
||||
<div class="col-sm-4 col-xs-12">
|
||||
<div class="btn-group pull-right mode-buttons">
|
||||
{{{modeButtons}}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div class="timeline"></div>
|
||||
@@ -0,0 +1 @@
|
||||
{{{value}}}
|
||||
@@ -0,0 +1,11 @@
|
||||
<div class="row">
|
||||
<div class="cell col-md-6">
|
||||
<div class="field" data-name="link">
|
||||
<select class="form-control" data-name="link">
|
||||
{{#each linkList}}
|
||||
<option value="{{./this}}">{{translate this category='links' scope='TargetList'}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
21
client/modules/crm/res/templates/campaign/unsubscribe.tpl
Normal file
21
client/modules/crm/res/templates/campaign/unsubscribe.tpl
Normal file
@@ -0,0 +1,21 @@
|
||||
<div class="container content">
|
||||
<div class="block-center-md">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<p>
|
||||
{{#if isSubscribed}}
|
||||
<a
|
||||
class="btn btn-primary{{#if inProcess}} disabled{{/if}}"
|
||||
data-action="unsubscribe"
|
||||
>{{translate 'Unsubscribe' scope='Campaign'}}</a>
|
||||
{{else}}
|
||||
<a
|
||||
class="btn btn-default{{#if inProcess}} disabled{{/if}}"
|
||||
data-action="subscribe"
|
||||
>{{translate 'Subscribe again' scope='Campaign'}}</a>
|
||||
{{/if}}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1 @@
|
||||
{{#if accountIsInactive}}<del>{{/if}}<span title="{{value}}">{{value}}</span>{{#if accountIsInactive}}</del>{{/if}}
|
||||
9
client/modules/crm/res/templates/document/list.tpl
Normal file
9
client/modules/crm/res/templates/document/list.tpl
Normal file
@@ -0,0 +1,9 @@
|
||||
<div class="page-header">{{{header}}}</div>
|
||||
<div class="search-container">{{{search}}}</div>
|
||||
|
||||
<div class="row">
|
||||
{{#unless categoriesDisabled}}
|
||||
<div class="categories-container{{#unless categoriesDisabled}} col-md-3 col-sm-4{{else}} col-md-12{{/unless}}">{{{categories}}}</div>
|
||||
{{/unless}}
|
||||
<div class="list-container{{#unless categoriesDisabled}} col-md-9 col-sm-8{{else}} col-md-12{{/unless}}">{{{list}}}</div>
|
||||
</div>
|
||||
@@ -0,0 +1,14 @@
|
||||
<div class="search-container">{{{search}}}</div>
|
||||
|
||||
<div class="row">
|
||||
{{#unless categoriesDisabled}}
|
||||
<div class="categories-container{{#unless categoriesDisabled}} col-md-3 col-sm-4{{else}} col-md-12{{/unless}}">{{{categories}}}</div>
|
||||
{{/unless}}
|
||||
<div class="list-container{{#unless categoriesDisabled}} col-md-9 col-sm-8{{else}} col-md-12{{/unless}}">{{{list}}}</div>
|
||||
</div>
|
||||
|
||||
{{#if createButton}}
|
||||
<div class="button-container">
|
||||
<button class="btn btn-default" data-action="create">{{translate 'Create'}}</button>
|
||||
</div>
|
||||
{{/if}}
|
||||
@@ -0,0 +1,36 @@
|
||||
<div class="container content">
|
||||
<div class="block-center-md">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<h4 class="margin-bottom-2x">{{actionData.translatedEntityType}}: {{actionData.eventName}}</h4>
|
||||
{{#if dateStart}}
|
||||
<div class="margin-bottom-2x">
|
||||
{{#if dateStartChanged}}
|
||||
<div style="text-decoration: line-through;">{{sentDateStart}}</div>
|
||||
{{/if}}
|
||||
<div>{{dateStart}}</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
<div>
|
||||
<span class="label label-{{style}} label-md">{{actionData.translatedStatus}}</span>
|
||||
<div class="btn-group">
|
||||
{{#if actionDataList}}
|
||||
<a role="button" class="dropdown-toggle text-soft" data-toggle="dropdown">
|
||||
<span class="fas fa-ellipsis-h"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
{{#each actionDataList}}
|
||||
<li>
|
||||
<a {{#if link}}href="{{link}}"{{/if}}>{{label}}
|
||||
{{#if active}}<span class="fas fa-check pull-right"></span>{{/if}}
|
||||
</a>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,10 @@
|
||||
<div class="page-header">{{{header}}}</div>
|
||||
<div class="search-container">{{{search}}}</div>
|
||||
|
||||
<div class="row">
|
||||
{{#unless categoriesDisabled}}
|
||||
<div class="categories-container{{#unless categoriesDisabled}} col-md-3 col-sm-4{{else}} col-md-12{{/unless}}">{{{categories}}}</div>
|
||||
{{/unless}}
|
||||
<div class="list-container{{#unless categoriesDisabled}} col-md-9 col-sm-8{{else}} col-md-12{{/unless}}">{{{list}}}</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<div class="search-container">{{{search}}}</div>
|
||||
|
||||
<div class="row">
|
||||
{{#unless categoriesDisabled}}
|
||||
<div class="categories-container{{#unless categoriesDisabled}} col-md-3 col-sm-4{{else}} col-md-12{{/unless}}">{{{categories}}}</div>
|
||||
{{/unless}}
|
||||
<div class="list-container{{#unless categoriesDisabled}} col-md-9 col-sm-8{{else}} col-md-12{{/unless}}">{{{list}}}</div>
|
||||
</div>
|
||||
|
||||
{{#if createButton}}
|
||||
<div class="button-container">
|
||||
<button class="btn btn-default" data-action="create">{{translate 'Create'}}</button>
|
||||
</div>
|
||||
{{/if}}
|
||||
24
client/modules/crm/res/templates/lead/convert.tpl
Normal file
24
client/modules/crm/res/templates/lead/convert.tpl
Normal file
@@ -0,0 +1,24 @@
|
||||
<div class="header page-header">{{{header}}}</div>
|
||||
|
||||
{{#each scopeList}}
|
||||
<div class="record">
|
||||
<label style="user-select: none; cursor: pointer;" class="text-large">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="check-scope form-checkbox"
|
||||
data-scope="{{./this}}"
|
||||
>
|
||||
<span>{{translate this category='scopeNames'}}</span>
|
||||
</label>
|
||||
<div class="edit-container-{{toDom this}} hide">
|
||||
{{{var this ../this}}}
|
||||
</div>
|
||||
</div>
|
||||
{{/each}}
|
||||
|
||||
<div class="button-container margin-top">
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-primary" data-action="convert">{{translate 'Convert' scope='Lead'}}</button>
|
||||
<button class="btn btn-default" data-action="cancel">{{translate 'Cancel'}}</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,5 @@
|
||||
{{#if value}}
|
||||
{{{value}}}
|
||||
{{else}}
|
||||
<span class="none-value">{{translate 'None'}}</span>
|
||||
{{/if}}
|
||||
@@ -0,0 +1,6 @@
|
||||
<div class="reminders-container"></div>
|
||||
<button
|
||||
data-action="addReminder"
|
||||
class="btn btn-default"
|
||||
type="button"
|
||||
><span class="fas fa-plus"></span></button>
|
||||
@@ -0,0 +1,39 @@
|
||||
{{#if closeButton~}}
|
||||
<a
|
||||
role="button"
|
||||
tabindex="0"
|
||||
class="pull-right close"
|
||||
data-action="close"
|
||||
aria-hidden="true"
|
||||
title="{{translate 'Close'}}"
|
||||
><span class="fas fa-times"></span></a>
|
||||
{{~/if~}}
|
||||
{{#if collapseButton~}}
|
||||
<a
|
||||
role="button"
|
||||
tabindex="0"
|
||||
class="pull-right text-muted"
|
||||
data-action="collapse"
|
||||
aria-hidden="true"
|
||||
title="{{translate 'Collapse'}}"
|
||||
><span class="fas fa-minus"></span></a>
|
||||
{{~/if}}
|
||||
<h4>{{header}}</h4>
|
||||
|
||||
|
||||
<div class="cell form-group">
|
||||
<div class="field">
|
||||
<a
|
||||
href="#{{notificationData.entityType}}/view/{{notificationData.id}}"
|
||||
data-action="close"
|
||||
>{{notificationData.name}}</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="cell form-group" data-name="{{dateField}}">
|
||||
<div class="field" data-name="{{dateField}}">
|
||||
{{{date}}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<div class="list-container">
|
||||
{{{list}}}
|
||||
</div>
|
||||
48
client/modules/crm/src/acl-portal/account.js
Normal file
48
client/modules/crm/src/acl-portal/account.js
Normal file
@@ -0,0 +1,48 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import AclPortal from 'acl-portal';
|
||||
|
||||
class AccountAclPortal extends AclPortal {
|
||||
|
||||
checkInAccount(model) {
|
||||
const accountIdList = this.getUser().getLinkMultipleIdList('accounts');
|
||||
|
||||
if (!accountIdList.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (~accountIdList.indexOf(model.id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export default AccountAclPortal;
|
||||
48
client/modules/crm/src/acl-portal/contact.js
Normal file
48
client/modules/crm/src/acl-portal/contact.js
Normal file
@@ -0,0 +1,48 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import AclPortal from 'acl-portal';
|
||||
|
||||
class ContactAclPortal extends AclPortal {
|
||||
|
||||
checkIsOwnContact(model) {
|
||||
const contactId = this.getUser().get('contactId');
|
||||
|
||||
if (!contactId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (contactId === model.id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export default ContactAclPortal;
|
||||
49
client/modules/crm/src/acl-portal/document.js
Normal file
49
client/modules/crm/src/acl-portal/document.js
Normal file
@@ -0,0 +1,49 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import AclPortal from 'acl-portal';
|
||||
|
||||
class DocumentAclPortal extends AclPortal {
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
checkModelEdit(model, data, precise) {
|
||||
let result = this.checkModel(model, data, 'delete', precise);
|
||||
|
||||
if (result) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (data.edit === 'account') {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export default DocumentAclPortal;
|
||||
33
client/modules/crm/src/acl/call.js
Normal file
33
client/modules/crm/src/acl/call.js
Normal file
@@ -0,0 +1,33 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import MeetingAcl from 'modules/crm/acl/meeting';
|
||||
|
||||
class CallAcl extends MeetingAcl {}
|
||||
|
||||
export default CallAcl;
|
||||
50
client/modules/crm/src/acl/campaign-tracking-url.js
Normal file
50
client/modules/crm/src/acl/campaign-tracking-url.js
Normal file
@@ -0,0 +1,50 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import Acl from 'acl';
|
||||
|
||||
class CampaignTrackingUrlAcl extends Acl {
|
||||
|
||||
checkIsOwner(model) {
|
||||
if (model.has('campaignId')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
checkInTeam(model) {
|
||||
if (model.has('campaignId')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export default CampaignTrackingUrlAcl;
|
||||
58
client/modules/crm/src/acl/mass-email.js
Normal file
58
client/modules/crm/src/acl/mass-email.js
Normal file
@@ -0,0 +1,58 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import Acl from 'acl';
|
||||
|
||||
class MassEmailAcl extends Acl {
|
||||
|
||||
checkScope(data, action, precise, entityAccessData) {
|
||||
if (action === 'create') {
|
||||
return super.checkScope(data, 'edit', precise, entityAccessData);
|
||||
}
|
||||
|
||||
return super.checkScope(data, action, precise, entityAccessData);
|
||||
}
|
||||
|
||||
checkIsOwner(model) {
|
||||
if (model.has('campaignId')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.checkIsOwner(model);
|
||||
}
|
||||
|
||||
checkInTeam(model) {
|
||||
if (model.has('campaignId')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.checkInTeam(model);
|
||||
}
|
||||
}
|
||||
|
||||
export default MassEmailAcl;
|
||||
74
client/modules/crm/src/acl/meeting.js
Normal file
74
client/modules/crm/src/acl/meeting.js
Normal file
@@ -0,0 +1,74 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import Acl from 'acl';
|
||||
|
||||
class MeetingAcl extends Acl {
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
checkModelRead(model, data, precise) {
|
||||
return this._checkModelCustom('read', model, data, precise);
|
||||
}
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
checkModelStream(model, data, precise) {
|
||||
return this._checkModelCustom('stream', model, data, precise);
|
||||
}
|
||||
|
||||
_checkModelCustom(action, model, data, precise) {
|
||||
let result = this.checkModel(model, data, action, precise);
|
||||
|
||||
if (result) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (data === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let d = data || {};
|
||||
|
||||
if (d[action] === 'no') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (model.has('usersIds')) {
|
||||
if (~(model.get('usersIds') || []).indexOf(this.getUser().id)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (precise) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
export default MeetingAcl;
|
||||
|
||||
73
client/modules/crm/src/controllers/activities.js
Normal file
73
client/modules/crm/src/controllers/activities.js
Normal file
@@ -0,0 +1,73 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import Controller from 'controller';
|
||||
|
||||
export default class ActivitiesController extends Controller {
|
||||
|
||||
checkAccess(action) {
|
||||
return this.getAcl().check('Activities');
|
||||
}
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
actionActivities(options) {
|
||||
this.processList('activities', options.entityType, options.id, options.targetEntityType);
|
||||
}
|
||||
|
||||
actionHistory(options) {
|
||||
this.processList('history', options.entityType, options.id, options.targetEntityType);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {'activities'|'history'} type
|
||||
* @param {string} entityType
|
||||
* @param {string} id
|
||||
* @param {string} targetEntityType
|
||||
*/
|
||||
async processList(type, entityType, id, targetEntityType) {
|
||||
const viewName = 'modules/crm/views/activities/list';
|
||||
|
||||
const model = await this.modelFactory.create(entityType)
|
||||
|
||||
model.id = id;
|
||||
|
||||
await model.fetch({main: true});
|
||||
|
||||
const collection = await this.collectionFactory.create(targetEntityType);
|
||||
collection.url = `Activities/${model.entityType}/${id}/${type}/list/${targetEntityType}`;
|
||||
|
||||
this.main(viewName, {
|
||||
scope: entityType,
|
||||
model: model,
|
||||
collection: collection,
|
||||
link: `${type}_${targetEntityType}`,
|
||||
type: type,
|
||||
});
|
||||
}
|
||||
}
|
||||
58
client/modules/crm/src/controllers/calendar.js
Normal file
58
client/modules/crm/src/controllers/calendar.js
Normal file
@@ -0,0 +1,58 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import Controller from 'controller';
|
||||
|
||||
class CalendarController extends Controller {
|
||||
|
||||
checkAccess() {
|
||||
if (this.getAcl().check('Calendar')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
actionShow(options) {
|
||||
this.actionIndex(options);
|
||||
}
|
||||
|
||||
actionIndex(options) {
|
||||
this.handleCheckAccess('');
|
||||
|
||||
this.main('crm:views/calendar/calendar-page', {
|
||||
date: options.date,
|
||||
mode: options.mode,
|
||||
userId: options.userId,
|
||||
userName: options.userName,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default CalendarController;
|
||||
47
client/modules/crm/src/controllers/event-confirmation.js
Normal file
47
client/modules/crm/src/controllers/event-confirmation.js
Normal file
@@ -0,0 +1,47 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import Controller from 'controller';
|
||||
|
||||
class EventConfirmationController extends Controller {
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
actionConfirmEvent(actionData) {
|
||||
const viewName = this.getMetadata().get(['clientDefs', 'EventConfirmation', 'confirmationView']) ||
|
||||
'crm:views/event-confirmation/confirmation';
|
||||
|
||||
this.entire(viewName, {
|
||||
actionData: actionData,
|
||||
}, view => {
|
||||
view.render();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
export default EventConfirmationController;
|
||||
39
client/modules/crm/src/controllers/lead.js
Normal file
39
client/modules/crm/src/controllers/lead.js
Normal file
@@ -0,0 +1,39 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import RecordController from 'controllers/record';
|
||||
|
||||
class LeadController extends RecordController {
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
actionConvert(options) {
|
||||
this.main('crm:views/lead/convert', {id: options.id});
|
||||
}
|
||||
}
|
||||
|
||||
export default LeadController;
|
||||
44
client/modules/crm/src/controllers/task.js
Normal file
44
client/modules/crm/src/controllers/task.js
Normal file
@@ -0,0 +1,44 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import RecordController from 'controllers/record';
|
||||
|
||||
export default class TaskController extends RecordController {
|
||||
|
||||
actionCreate(options) {
|
||||
const attributes = {...options.attributes};
|
||||
|
||||
if (options.emailId) {
|
||||
attributes.emailId = options.emailId;
|
||||
|
||||
options.attributes = attributes;
|
||||
}
|
||||
|
||||
super.actionCreate(options);
|
||||
}
|
||||
}
|
||||
46
client/modules/crm/src/controllers/tracking-url.js
Normal file
46
client/modules/crm/src/controllers/tracking-url.js
Normal file
@@ -0,0 +1,46 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import Controller from 'controller';
|
||||
|
||||
class TrackingUrlController extends Controller {
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
actionDisplayMessage(data) {
|
||||
const viewName = data.view || 'crm:views/campaign/tracking-url';
|
||||
|
||||
this.entire(viewName, {
|
||||
message: data.message,
|
||||
template: data.template,
|
||||
}, view => {
|
||||
view.render();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default TrackingUrlController
|
||||
46
client/modules/crm/src/controllers/unsubscribe.js
Normal file
46
client/modules/crm/src/controllers/unsubscribe.js
Normal file
@@ -0,0 +1,46 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import Controller from 'controller';
|
||||
|
||||
class UnsubscribeController extends Controller {
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
actionUnsubscribe(data) {
|
||||
const viewName = data.view || 'crm:views/campaign/unsubscribe';
|
||||
|
||||
this.entire(viewName, {
|
||||
actionData: data.actionData,
|
||||
template: data.template,
|
||||
}, view => {
|
||||
view.render();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default UnsubscribeController;
|
||||
@@ -0,0 +1,40 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import CreateRelated from 'handlers/create-related';
|
||||
|
||||
class MassEmailsCreateHandler extends CreateRelated {
|
||||
|
||||
getAttributes(model) {
|
||||
return Promise.resolve({
|
||||
name: model.get('name') + ' ' + this.viewHelper.dateTime.getToday(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default MassEmailsCreateHandler;
|
||||
91
client/modules/crm/src/handlers/case/detail-actions.js
Normal file
91
client/modules/crm/src/handlers/case/detail-actions.js
Normal file
@@ -0,0 +1,91 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import ActionHandler from 'action-handler';
|
||||
|
||||
class CaseDetailActionHandler extends ActionHandler {
|
||||
|
||||
close() {
|
||||
const model = this.view.model;
|
||||
|
||||
model.save({status: 'Closed'}, {patch: true})
|
||||
.then(() => {
|
||||
Espo.Ui.success(this.view.translate('Closed', 'labels', 'Case'));
|
||||
});
|
||||
}
|
||||
|
||||
reject() {
|
||||
const model = this.view.model;
|
||||
|
||||
model.save({status: 'Rejected'}, {patch: true})
|
||||
.then(() => {
|
||||
Espo.Ui.success(this.view.translate('Rejected', 'labels', 'Case'));
|
||||
});
|
||||
}
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
isCloseAvailable() {
|
||||
return this.isStatusAvailable('Closed');
|
||||
}
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
isRejectAvailable() {
|
||||
return this.isStatusAvailable('Rejected');
|
||||
}
|
||||
|
||||
isStatusAvailable(status) {
|
||||
const model = this.view.model;
|
||||
const acl = this.view.getAcl();
|
||||
const metadata = this.view.getMetadata();
|
||||
|
||||
/** @type {string[]} */
|
||||
const notActualStatuses = metadata.get('entityDefs.Case.fields.status.notActualOptions') || [];
|
||||
|
||||
if (notActualStatuses.includes(model.get('status'))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!acl.check(model, 'edit')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!acl.checkField(model.entityType, 'status', 'edit')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const statusList = metadata.get(['entityDefs', 'Case', 'fields', 'status', 'options']) || [];
|
||||
|
||||
if (!statusList.includes(status)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export default CaseDetailActionHandler;
|
||||
93
client/modules/crm/src/handlers/event/reminders-handler.js
Normal file
93
client/modules/crm/src/handlers/event/reminders-handler.js
Normal file
@@ -0,0 +1,93 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import {Events} from 'bullbone';
|
||||
|
||||
/**
|
||||
* @mixes Bull.Events
|
||||
*/
|
||||
class RemindersHandler {
|
||||
|
||||
/**
|
||||
* @param {import('views/record/detail').default} view
|
||||
*/
|
||||
constructor(view) {
|
||||
this.view = view;
|
||||
/** @type {import('model').default} */
|
||||
this.model = view.model;
|
||||
/** @type {import('models/user').default} */
|
||||
this.user = this.view.getUser();
|
||||
|
||||
this.ignoreStatusList = [
|
||||
...(this.view.getMetadata().get(['scopes', this.view.entityType, 'completedStatusList']) || []),
|
||||
...(this.view.getMetadata().get(['scopes', this.view.entityType, 'canceledStatusList']) || []),
|
||||
];
|
||||
}
|
||||
|
||||
process() {
|
||||
this.control();
|
||||
|
||||
this.listenTo(this.model, 'change', () => {
|
||||
if (
|
||||
!this.model.hasChanged('assignedUserId') &&
|
||||
!this.model.hasChanged('usersIds') &&
|
||||
!this.model.hasChanged('assignedUsersIds') &&
|
||||
!this.model.hasChanged('status')
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.control();
|
||||
});
|
||||
}
|
||||
|
||||
control() {
|
||||
const usersIds = /** @type {string[]} */this.model.get('usersIds') || [];
|
||||
const assignedUsersIds = /** @type {string[]} */this.model.get('assignedUsersIds') || [];
|
||||
|
||||
if (
|
||||
!this.ignoreStatusList.includes(this.model.get('status')) &&
|
||||
(
|
||||
this.model.get('assignedUserId') === this.user.id ||
|
||||
usersIds.includes(this.user.id) ||
|
||||
assignedUsersIds.includes(this.user.id)
|
||||
)
|
||||
) {
|
||||
this.view.showField('reminders');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.view.hideField('reminders');
|
||||
}
|
||||
}
|
||||
|
||||
Object.assign(RemindersHandler.prototype, Events);
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
export default RemindersHandler;
|
||||
136
client/modules/crm/src/handlers/knowledge-base-article/move.js
Normal file
136
client/modules/crm/src/handlers/knowledge-base-article/move.js
Normal file
@@ -0,0 +1,136 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import RowActionHandler from 'handlers/row-action';
|
||||
|
||||
class MoveActionHandler extends RowActionHandler {
|
||||
|
||||
isAvailable(model, action) {
|
||||
return model.collection &&
|
||||
model.collection.orderBy === 'order' &&
|
||||
model.collection.order === 'asc';
|
||||
}
|
||||
|
||||
process(model, action) {
|
||||
if (action === 'moveToTop') {
|
||||
this.moveToTop(model);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (action === 'moveToBottom') {
|
||||
this.moveToBottom(model);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (action === 'moveUp') {
|
||||
this.moveUp(model);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (action === 'moveDown') {
|
||||
this.moveDown(model);
|
||||
}
|
||||
}
|
||||
|
||||
moveToTop(model) {
|
||||
const index = this.collection.indexOf(model);
|
||||
|
||||
if (index === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Espo.Ui.notifyWait();
|
||||
|
||||
Espo.Ajax.postRequest('KnowledgeBaseArticle/action/moveToTop', {
|
||||
id: model.id,
|
||||
whereGroup: this.collection.getWhere(),
|
||||
}).then(() => {
|
||||
this.collection.fetch()
|
||||
.then(() => Espo.Ui.notify(false));
|
||||
});
|
||||
}
|
||||
|
||||
moveUp(model) {
|
||||
const index = this.collection.indexOf(model);
|
||||
|
||||
if (index === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Espo.Ui.notifyWait();
|
||||
|
||||
Espo.Ajax.postRequest('KnowledgeBaseArticle/action/moveUp', {
|
||||
id: model.id,
|
||||
whereGroup: this.collection.getWhere(),
|
||||
}).then(() => {
|
||||
this.collection.fetch()
|
||||
.then(() => Espo.Ui.notify(false));
|
||||
});
|
||||
}
|
||||
|
||||
moveDown(model) {
|
||||
const index = this.collection.indexOf(model);
|
||||
|
||||
if ((index === this.collection.length - 1) && (this.collection.length === this.collection.total)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Espo.Ui.notifyWait();
|
||||
|
||||
Espo.Ajax.postRequest('KnowledgeBaseArticle/action/moveDown', {
|
||||
id: model.id,
|
||||
whereGroup: this.collection.getWhere(),
|
||||
}).then(() => {
|
||||
this.collection.fetch()
|
||||
.then(() => Espo.Ui.notify(false));
|
||||
});
|
||||
}
|
||||
|
||||
moveToBottom(model) {
|
||||
const index = this.collection.indexOf(model);
|
||||
|
||||
if ((index === this.collection.length - 1) && (this.collection.length === this.collection.total)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Espo.Ui.notifyWait();
|
||||
|
||||
Espo.Ajax.postRequest('KnowledgeBaseArticle/action/moveToBottom', {
|
||||
id: model.id,
|
||||
whereGroup: this.collection.getWhere(),
|
||||
}).then(() => {
|
||||
this.collection.fetch()
|
||||
.then(() => Espo.Ui.notify(false));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default MoveActionHandler;
|
||||
@@ -0,0 +1,149 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import RowActionHandler from 'handlers/row-action';
|
||||
|
||||
class SendInEmailHandler extends RowActionHandler {
|
||||
|
||||
isAvailable(model, action) {
|
||||
return this.view.getAcl().checkScope('Email', 'create');
|
||||
}
|
||||
|
||||
process(model, action) {
|
||||
const parentModel = this.view.getParentView().model;
|
||||
const modelFactory = this.view.getModelFactory();
|
||||
const collectionFactory = this.view.getCollectionFactory();
|
||||
|
||||
Espo.Ui.notifyWait();
|
||||
|
||||
model.fetch()
|
||||
.then(() => {
|
||||
return new Promise(resolve => {
|
||||
if (
|
||||
parentModel.get('contactsIds') &&
|
||||
parentModel.get('contactsIds').length
|
||||
) {
|
||||
collectionFactory.create('Contact', contactList => {
|
||||
const contactListFinal = [];
|
||||
contactList.url = 'Case/' + parentModel.id + '/contacts';
|
||||
|
||||
contactList.fetch().then(() => {
|
||||
contactList.forEach(contact => {
|
||||
if (contact.id === parentModel.get('contactId')) {
|
||||
contactListFinal.unshift(contact);
|
||||
} else {
|
||||
contactListFinal.push(contact);
|
||||
}
|
||||
});
|
||||
|
||||
resolve(contactListFinal);
|
||||
});
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (parentModel.get('accountId')) {
|
||||
modelFactory.create('Account', account => {
|
||||
account.id = parentModel.get('accountId');
|
||||
|
||||
account.fetch()
|
||||
.then(() => resolve([account]));
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (parentModel.get('leadId')) {
|
||||
modelFactory.create('Lead', lead => {
|
||||
lead.id = parentModel.get('leadId');
|
||||
|
||||
lead.fetch()
|
||||
.then(() => resolve([lead]));
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
resolve([]);
|
||||
});
|
||||
})
|
||||
.then(list => {
|
||||
const attributes = {
|
||||
parentType: 'Case',
|
||||
parentId: parentModel.id,
|
||||
parentName: parentModel.get('name'),
|
||||
name: '[#' + parentModel.get('number') + ']',
|
||||
};
|
||||
|
||||
attributes.to = '';
|
||||
attributes.cc = '';
|
||||
attributes.nameHash = {};
|
||||
|
||||
list.forEach((model, i) => {
|
||||
if (model.get('emailAddress')) {
|
||||
if (i === 0) {
|
||||
attributes.to += model.get('emailAddress') + ';';
|
||||
} else {
|
||||
attributes.cc += model.get('emailAddress') + ';';
|
||||
}
|
||||
|
||||
attributes.nameHash[model.get('emailAddress')] = model.get('name');
|
||||
}
|
||||
});
|
||||
|
||||
Espo.loader.require('crm:knowledge-base-helper', Helper => {
|
||||
const helper = new Helper(this.view.getLanguage());
|
||||
|
||||
helper.getAttributesForEmail(model, attributes, attributes => {
|
||||
const viewName = this.view.getMetadata().get('clientDefs.Email.modalViews.compose') ||
|
||||
'views/modals/compose-email';
|
||||
|
||||
this.view.createView('composeEmail', viewName, {
|
||||
attributes: attributes,
|
||||
selectTemplateDisabled: true,
|
||||
signatureDisabled: true,
|
||||
}, view => {
|
||||
Espo.Ui.notify(false);
|
||||
|
||||
view.render();
|
||||
|
||||
this.view.listenToOnce(view, 'after:send', () => {
|
||||
parentModel.trigger('after:relate');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
Espo.Ui.notify(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default SendInEmailHandler;
|
||||
72
client/modules/crm/src/handlers/meeting/external-service.js
Normal file
72
client/modules/crm/src/handlers/meeting/external-service.js
Normal file
@@ -0,0 +1,72 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import {inject} from 'di';
|
||||
import AppParams from 'app-params';
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
export default class MeetingExternalServiceHandler{
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {AppParams}
|
||||
*/
|
||||
@inject(AppParams)
|
||||
appParams
|
||||
|
||||
/**
|
||||
* @param {import('views/record/detail').default} view
|
||||
*/
|
||||
constructor(view) {
|
||||
this.view = view;
|
||||
}
|
||||
|
||||
process() {
|
||||
this.controlField();
|
||||
this.view.listenTo(this.view.model, 'change:externalService', () => this.controlField());
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
controlField() {
|
||||
const model = this.view.model;
|
||||
|
||||
if (model.attributes.externalService) {
|
||||
this.view.showField('externalService');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const list = this.appParams.get('meetingServices') ?? [];
|
||||
|
||||
if (!list.length) {
|
||||
this.view.hideField('externalService');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import CreateRelated from 'handlers/create-related';
|
||||
|
||||
class ContactsCreateHandler extends CreateRelated {
|
||||
|
||||
getAttributes(model) {
|
||||
const attributes = {};
|
||||
|
||||
if (model.get('accountId')) {
|
||||
attributes['accountsIds'] = [model.get('accountId')]
|
||||
}
|
||||
|
||||
return Promise.resolve(attributes);
|
||||
}
|
||||
}
|
||||
|
||||
export default ContactsCreateHandler;
|
||||
@@ -0,0 +1,56 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import DefaultsPreparator from 'handlers/model/defaults-preparator';
|
||||
import Metadata from 'metadata';
|
||||
import {inject} from 'di';
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
export default class extends DefaultsPreparator {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Metadata}
|
||||
*/
|
||||
@inject(Metadata)
|
||||
metadata
|
||||
|
||||
prepare(model) {
|
||||
const probabilityMap = this.metadata.get('entityDefs.Opportunity.fields.stage.probabilityMap') || {};
|
||||
const stage = model.attributes.stage;
|
||||
|
||||
const attributes = {};
|
||||
|
||||
if (stage in probabilityMap) {
|
||||
attributes.probability = probabilityMap[stage];
|
||||
}
|
||||
|
||||
return Promise.resolve(attributes);
|
||||
}
|
||||
}
|
||||
|
||||
89
client/modules/crm/src/handlers/task/detail-actions.js
Normal file
89
client/modules/crm/src/handlers/task/detail-actions.js
Normal file
@@ -0,0 +1,89 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import ActionHandler from 'action-handler';
|
||||
import {inject} from 'di';
|
||||
import Metadata from 'metadata';
|
||||
import Ui from 'ui';
|
||||
|
||||
class DetailActions extends ActionHandler {
|
||||
|
||||
/**
|
||||
* @type {string[]}
|
||||
* @private
|
||||
*/
|
||||
historyStatusList
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string|null}
|
||||
*/
|
||||
completedStatusValue
|
||||
|
||||
@inject(Metadata)
|
||||
metadata
|
||||
|
||||
constructor(view) {
|
||||
super(view);
|
||||
|
||||
/** @var string[]*/
|
||||
const completedStatusList = this.metadata.get(`scopes.Task.completedStatusList`, []);
|
||||
|
||||
this.historyStatusList = [
|
||||
...completedStatusList,
|
||||
...this.metadata.get(`scopes.Task.canceledStatusList`, []),
|
||||
];
|
||||
|
||||
this.completedStatusValue = completedStatusList[0] ?? null;
|
||||
}
|
||||
|
||||
async complete() {
|
||||
const model = this.view.model;
|
||||
|
||||
Ui.notifyWait();
|
||||
|
||||
await model.save({status: this.completedStatusValue}, {patch: true});
|
||||
|
||||
// Needed for calendar update.
|
||||
this.view.trigger('after:save', model);
|
||||
|
||||
Ui.success(this.view.getLanguage().translateOption('Completed', 'status', 'Task'));
|
||||
}
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
/**
|
||||
* @return {boolean}
|
||||
*/
|
||||
isCompleteAvailable() {
|
||||
const status = this.view.model.attributes.status;
|
||||
|
||||
return !this.historyStatusList.includes(status);
|
||||
}
|
||||
}
|
||||
|
||||
export default DetailActions;
|
||||
90
client/modules/crm/src/handlers/task/menu.js
Normal file
90
client/modules/crm/src/handlers/task/menu.js
Normal file
@@ -0,0 +1,90 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import ActionHandler from 'action-handler';
|
||||
import {inject} from 'di';
|
||||
import Metadata from 'metadata';
|
||||
import Ui from 'ui';
|
||||
|
||||
export default class TaskMenuHandler extends ActionHandler {
|
||||
|
||||
/**
|
||||
* @type {string[]}
|
||||
* @private
|
||||
*/
|
||||
historyStatusList
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string|null}
|
||||
*/
|
||||
completedStatusValue
|
||||
|
||||
@inject(Metadata)
|
||||
metadata
|
||||
|
||||
constructor(view) {
|
||||
super(view);
|
||||
|
||||
/** @var string[]*/
|
||||
const completedStatusList = this.metadata.get(`scopes.Task.completedStatusList`, []);
|
||||
|
||||
this.historyStatusList = [
|
||||
...completedStatusList,
|
||||
...this.metadata.get(`scopes.Task.canceledStatusList`, []),
|
||||
];
|
||||
|
||||
this.completedStatusValue = completedStatusList[0] ?? null;
|
||||
}
|
||||
|
||||
async complete() {
|
||||
const model = this.view.model;
|
||||
|
||||
Ui.notifyWait();
|
||||
|
||||
await model.save({status: this.completedStatusValue}, {patch: true});
|
||||
|
||||
Ui.success(this.view.getLanguage().translateOption('Completed', 'status', 'Task'));
|
||||
}
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
/**
|
||||
* @return {boolean}
|
||||
*/
|
||||
isCompleteAvailable() {
|
||||
const status = this.view.model.attributes.status;
|
||||
|
||||
const view = /** @type {import('views/detail').default} */this.view;
|
||||
|
||||
if (view.getRecordView().isEditMode()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !this.historyStatusList.includes(status);
|
||||
}
|
||||
}
|
||||
97
client/modules/crm/src/handlers/task/reminders-handler.js
Normal file
97
client/modules/crm/src/handlers/task/reminders-handler.js
Normal file
@@ -0,0 +1,97 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import {Events} from 'bullbone';
|
||||
|
||||
/**
|
||||
* @mixes Bull.Events
|
||||
*/
|
||||
class RemindersHandler {
|
||||
|
||||
/**
|
||||
* @param {import('views/record/detail').default} view
|
||||
*/
|
||||
constructor(view) {
|
||||
this.view = view;
|
||||
this.model = view.model;
|
||||
this.user = this.view.getUser();
|
||||
|
||||
this.ignoreStatusList = [
|
||||
...(this.view.getMetadata().get(['scopes', this.view.entityType, 'completedStatusList']) || []),
|
||||
...(this.view.getMetadata().get(['scopes', this.view.entityType, 'canceledStatusList']) || []),
|
||||
];
|
||||
}
|
||||
|
||||
process() {
|
||||
this.control();
|
||||
|
||||
this.listenTo(this.model, 'change', () => {
|
||||
if (
|
||||
!this.model.hasChanged('assignedUserId') &&
|
||||
!this.model.hasChanged('assignedUsersIds') &&
|
||||
!this.model.hasChanged('dateEnd') &&
|
||||
!this.model.hasChanged('dateEndDate') &&
|
||||
!this.model.hasChanged('status')
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.control();
|
||||
});
|
||||
}
|
||||
|
||||
control() {
|
||||
if (!this.model.attributes.dateEnd && !this.model.attributes.dateEndDate) {
|
||||
this.view.hideField('reminders');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/** @type {string[]} */
|
||||
const assignedUsersIds = this.model.attributes.assignedUsersIds || [];
|
||||
|
||||
if (
|
||||
!this.ignoreStatusList.includes(this.model.attributes.status) &&
|
||||
(
|
||||
this.model.attributes.assignedUserId === this.user.id ||
|
||||
assignedUsersIds.includes(this.user.id)
|
||||
)
|
||||
) {
|
||||
this.view.showField('reminders');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.view.hideField('reminders');
|
||||
}
|
||||
}
|
||||
|
||||
Object.assign(RemindersHandler.prototype, Events);
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
export default RemindersHandler;
|
||||
70
client/modules/crm/src/knowledge-base-helper.js
Normal file
70
client/modules/crm/src/knowledge-base-helper.js
Normal file
@@ -0,0 +1,70 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import Ajax from 'ajax';
|
||||
|
||||
/**
|
||||
* @todo Move to modules/crm/helpers.
|
||||
*/
|
||||
class KnowledgeBaseHelper {
|
||||
|
||||
/**
|
||||
* @param {module:language} language
|
||||
*/
|
||||
constructor(language) {
|
||||
this.language = language;
|
||||
}
|
||||
|
||||
getAttributesForEmail(model, attributes, callback) {
|
||||
attributes = attributes || {};
|
||||
attributes.body = model.get('body');
|
||||
|
||||
if (attributes.name) {
|
||||
attributes.name = attributes.name + ' ';
|
||||
} else {
|
||||
attributes.name = '';
|
||||
}
|
||||
|
||||
attributes.name += this.language.translate('KnowledgeBaseArticle', 'scopeNames') + ': ' +
|
||||
model.get('name');
|
||||
|
||||
Ajax.postRequest('KnowledgeBaseArticle/action/getCopiedAttachments', {
|
||||
id: model.id,
|
||||
parentType: 'Email',
|
||||
field : 'attachments',
|
||||
}).then(data => {
|
||||
attributes.attachmentsIds = data.ids;
|
||||
attributes.attachmentsNames = data.names;
|
||||
attributes.isHtml = true;
|
||||
|
||||
callback(attributes);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default KnowledgeBaseHelper;
|
||||
@@ -0,0 +1,212 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import _ from 'underscore';
|
||||
import {Events} from 'bullbone';
|
||||
|
||||
const Handler = function (view) {
|
||||
this.view = view;
|
||||
};
|
||||
|
||||
_.extend(Handler.prototype, {
|
||||
|
||||
process: function () {
|
||||
this.listenTo(this.view, 'after:render', () => this.initDragDrop());
|
||||
this.listenTo(this.view, 'remove', () => this.disable());
|
||||
},
|
||||
|
||||
disable: function () {
|
||||
const $el = this.view.$el.parent();
|
||||
/** @type {Element} */
|
||||
const el = $el.get(0);
|
||||
|
||||
$el.off('drop');
|
||||
|
||||
if (!el) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.onDragoverBind) {
|
||||
return;
|
||||
}
|
||||
|
||||
el.removeEventListener('dragover', this.onDragoverBind);
|
||||
el.removeEventListener('dragenter', this.onDragenterBind);
|
||||
el.removeEventListener('dragleave', this.onDragleaveBind);
|
||||
},
|
||||
|
||||
initDragDrop: function () {
|
||||
this.disable();
|
||||
|
||||
const $el = this.view.$el.parent();
|
||||
const el = $el.get(0);
|
||||
|
||||
$el.on('drop', e => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
e = e.originalEvent;
|
||||
|
||||
if (
|
||||
e.dataTransfer &&
|
||||
e.dataTransfer.files &&
|
||||
e.dataTransfer.files.length === 1 &&
|
||||
this.dropEntered
|
||||
) {
|
||||
this.removeDrop();
|
||||
|
||||
this.create(e.dataTransfer.files[0]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.removeDrop($el);
|
||||
});
|
||||
|
||||
|
||||
this.dropEntered = false;
|
||||
|
||||
this.onDragoverBind = this.onDragover.bind(this);
|
||||
this.onDragenterBind = this.onDragenter.bind(this);
|
||||
this.onDragleaveBind = this.onDragleave.bind(this);
|
||||
|
||||
el.addEventListener('dragover', this.onDragoverBind);
|
||||
el.addEventListener('dragenter', this.onDragenterBind);
|
||||
el.addEventListener('dragleave', this.onDragleaveBind);
|
||||
},
|
||||
|
||||
renderDrop: function () {
|
||||
this.dropEntered = true;
|
||||
|
||||
const $backdrop =
|
||||
$('<div class="dd-backdrop">')
|
||||
.css('pointer-events', 'none')
|
||||
.append('<span class="fas fa-paperclip"></span>')
|
||||
.append(' ')
|
||||
.append(
|
||||
$('<span>')
|
||||
.text(this.view.getLanguage().translate('Create Document', 'labels', 'Document'))
|
||||
);
|
||||
|
||||
this.view.$el.append($backdrop);
|
||||
},
|
||||
|
||||
removeDrop: function () {
|
||||
this.view.$el.find('> .dd-backdrop').remove();
|
||||
|
||||
this.dropEntered = false;
|
||||
},
|
||||
|
||||
create: function (file) {
|
||||
this.view
|
||||
.actionQuickCreate()
|
||||
.then(view => {
|
||||
const fileView = view.getRecordView().getFieldView('file');
|
||||
|
||||
if (!fileView) {
|
||||
const msg = "No 'file' field on the layout.";
|
||||
|
||||
Espo.Ui.error(msg);
|
||||
console.error(msg);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (fileView.isRendered()) {
|
||||
fileView.uploadFile(file);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.listenToOnce(fileView, 'after:render', () => {
|
||||
fileView.uploadFile(file);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {DragEvent} e
|
||||
*/
|
||||
onDragover: function (e) {
|
||||
e.preventDefault();
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {DragEvent} e
|
||||
*/
|
||||
onDragenter: function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
if (!e.dataTransfer.types || !e.dataTransfer.types.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!~e.dataTransfer.types.indexOf('Files')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.dropEntered) {
|
||||
this.renderDrop();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {DragEvent} e
|
||||
*/
|
||||
onDragleave: function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
if (!this.dropEntered) {
|
||||
return;
|
||||
}
|
||||
|
||||
let fromElement = e.fromElement || e.relatedTarget;
|
||||
|
||||
if (
|
||||
fromElement &&
|
||||
$.contains(this.view.$el.parent().get(0), fromElement)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
fromElement &&
|
||||
fromElement.parentNode &&
|
||||
fromElement.parentNode.toString() === '[object ShadowRoot]'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.removeDrop();
|
||||
},
|
||||
});
|
||||
|
||||
Object.assign(Handler.prototype, Events);
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
export default Handler;
|
||||
32
client/modules/crm/src/views/account/detail.js
Normal file
32
client/modules/crm/src/views/account/detail.js
Normal file
@@ -0,0 +1,32 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import DetailView from 'views/detail';
|
||||
|
||||
/** Left for bc. */
|
||||
export default class extends DetailView {}
|
||||
135
client/modules/crm/src/views/account/fields/shipping-address.js
Normal file
135
client/modules/crm/src/views/account/fields/shipping-address.js
Normal file
@@ -0,0 +1,135 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import AddressFieldView from 'views/fields/address';
|
||||
|
||||
export default class extends AddressFieldView {
|
||||
|
||||
copyFrom = 'billingAddress'
|
||||
|
||||
setup() {
|
||||
super.setup();
|
||||
|
||||
this.addActionHandler('copyFromBilling', () => this.copy());
|
||||
|
||||
this.attributePartList = this.getMetadata().get(['fields', 'address', 'actualFields']) || [];
|
||||
|
||||
this.allAddressAttributeList = [];
|
||||
|
||||
this.attributePartList.forEach(part => {
|
||||
this.allAddressAttributeList.push(this.copyFrom + Espo.Utils.upperCaseFirst(part));
|
||||
this.allAddressAttributeList.push(this.name + Espo.Utils.upperCaseFirst(part));
|
||||
});
|
||||
|
||||
this.listenTo(this.model, 'change', () => {
|
||||
let isChanged = false;
|
||||
|
||||
for (const attribute of this.allAddressAttributeList) {
|
||||
if (this.model.hasChanged(attribute)) {
|
||||
isChanged = true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isChanged) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.isEditMode() || !this.isRendered() || !this.copyButtonElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.toShowCopyButton()) {
|
||||
this.copyButtonElement.classList.remove('hidden');
|
||||
} else {
|
||||
this.copyButtonElement.classList.add('hidden');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
afterRender() {
|
||||
super.afterRender();
|
||||
|
||||
if (this.mode === this.MODE_EDIT && this.element) {
|
||||
const label = this.translate('Copy Billing', 'labels', 'Account');
|
||||
|
||||
const button = this.copyButtonElement = document.createElement('button');
|
||||
|
||||
button.classList.add('btn', 'btn-default', 'btn-sm', 'action');
|
||||
button.textContent = label;
|
||||
button.setAttribute('data-action', 'copyFromBilling')
|
||||
|
||||
if (!this.toShowCopyButton()) {
|
||||
button.classList.add('hidden');
|
||||
}
|
||||
|
||||
this.element.append(button);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
copy() {
|
||||
const fieldFrom = this.copyFrom;
|
||||
|
||||
Object.keys(this.getMetadata().get('fields.address.fields') || {})
|
||||
.forEach(attr => {
|
||||
const destField = this.name + Espo.Utils.upperCaseFirst(attr);
|
||||
const sourceField = fieldFrom + Espo.Utils.upperCaseFirst(attr);
|
||||
|
||||
this.model.set(destField, this.model.get(sourceField));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @return {boolean}
|
||||
*/
|
||||
toShowCopyButton() {
|
||||
let billingIsNotEmpty = false;
|
||||
let shippingIsNotEmpty = false;
|
||||
|
||||
this.attributePartList.forEach(part => {
|
||||
const attribute1 = this.copyFrom + Espo.Utils.upperCaseFirst(part);
|
||||
|
||||
if (this.model.get(attribute1)) {
|
||||
billingIsNotEmpty = true;
|
||||
}
|
||||
|
||||
const attribute2 = this.name + Espo.Utils.upperCaseFirst(part);
|
||||
|
||||
if (this.model.get(attribute2)) {
|
||||
shippingIsNotEmpty = true;
|
||||
}
|
||||
});
|
||||
|
||||
return billingIsNotEmpty && !shippingIsNotEmpty;
|
||||
}
|
||||
}
|
||||
113
client/modules/crm/src/views/activities/list.js
Normal file
113
client/modules/crm/src/views/activities/list.js
Normal file
@@ -0,0 +1,113 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import ListRelatedView from 'views/list-related';
|
||||
|
||||
export default class ActivitiesListView extends ListRelatedView {
|
||||
|
||||
createButton = false
|
||||
unlinkDisabled = true
|
||||
filtersDisabled = true
|
||||
allResultDisabled = true;
|
||||
|
||||
setup() {
|
||||
this.rowActionsView = 'views/record/row-actions/default';
|
||||
|
||||
super.setup();
|
||||
|
||||
this.type = this.options.type;
|
||||
}
|
||||
|
||||
getHeader() {
|
||||
const name = this.model.get('name') || this.model.id;
|
||||
|
||||
const recordUrl = `#${this.scope}/view/${this.model.id}`;
|
||||
|
||||
const $name =
|
||||
$('<a>')
|
||||
.attr('href', recordUrl)
|
||||
.addClass('font-size-flexible title')
|
||||
.text(name)
|
||||
.css('user-select', 'none');
|
||||
|
||||
if (this.model.get('deleted')) {
|
||||
$name.css('text-decoration', 'line-through');
|
||||
}
|
||||
|
||||
const headerIconHtml = this.getHelper().getScopeColorIconHtml(this.foreignScope);
|
||||
const scopeLabel = this.getLanguage().translate(this.scope, 'scopeNamesPlural');
|
||||
|
||||
let $root = $('<span>').text(scopeLabel);
|
||||
|
||||
if (!this.rootLinkDisabled) {
|
||||
$root = $('<span>')
|
||||
.append(
|
||||
$('<a>')
|
||||
.attr('href', '#' + this.scope)
|
||||
.addClass('action')
|
||||
.attr('data-action', 'navigateToRoot')
|
||||
.text(scopeLabel)
|
||||
);
|
||||
}
|
||||
|
||||
$root.css('user-select', 'none');
|
||||
|
||||
if (headerIconHtml) {
|
||||
$root.prepend(headerIconHtml);
|
||||
}
|
||||
|
||||
const linkLabel = this.type === 'history' ? this.translate('History') : this.translate('Activities');
|
||||
|
||||
const $link = $('<span>').text(linkLabel);
|
||||
|
||||
$link
|
||||
.css('user-select', 'none');
|
||||
|
||||
const $target = $('<span>').text(this.translate(this.foreignScope, 'scopeNamesPlural'));
|
||||
|
||||
$target
|
||||
.css('user-select', 'none')
|
||||
.css('cursor', 'pointer')
|
||||
.attr('data-action', 'fullRefresh')
|
||||
.attr('title', this.translate('clickToRefresh', 'messages'))
|
||||
|
||||
return this.buildHeaderHtml([
|
||||
$root,
|
||||
$name,
|
||||
$link,
|
||||
$target,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
updatePageTitle() {
|
||||
this.setPageTitle(this.translate(this.foreignScope, 'scopeNamesPlural'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import MultiEnumFieldView from 'views/fields/multi-enum';
|
||||
|
||||
export default class extends MultiEnumFieldView {
|
||||
|
||||
setupOptions() {
|
||||
const entityType = this.model.get('name');
|
||||
|
||||
const options = this.getMetadata().get(['entityDefs', entityType, 'fields', 'status', 'options']) || [];
|
||||
|
||||
this.params.options = [...options];
|
||||
this.params.translation = `${entityType}.options.status`;
|
||||
}
|
||||
}
|
||||
601
client/modules/crm/src/views/calendar/calendar-page.js
Normal file
601
client/modules/crm/src/views/calendar/calendar-page.js
Normal file
@@ -0,0 +1,601 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
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';
|
||||
import WebSocketManager from 'web-socket-manager';
|
||||
import Utils from 'utils';
|
||||
|
||||
class CalendarPage extends View {
|
||||
|
||||
template = 'crm:calendar/calendar-page'
|
||||
|
||||
//el = '#main'
|
||||
|
||||
fullCalendarModeList = [
|
||||
'month',
|
||||
'agendaWeek',
|
||||
'agendaDay',
|
||||
'basicWeek',
|
||||
'basicDay',
|
||||
'listWeek',
|
||||
]
|
||||
|
||||
events = {
|
||||
/** @this CalendarPage */
|
||||
'click [data-action="createCustomView"]': function () {
|
||||
this.createCustomView();
|
||||
},
|
||||
/** @this CalendarPage */
|
||||
'click [data-action="editCustomView"]': function () {
|
||||
this.editCustomView();
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {ShortcutManager}
|
||||
*/
|
||||
@inject(ShortcutManager)
|
||||
shortcutManager
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {DebounceHelper|null}
|
||||
*/
|
||||
webSocketDebounceHelper = null
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
webSocketDebounceInterval = 500
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
webSocketBlockInterval = 1000
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {WebSocketManager}
|
||||
*/
|
||||
@inject(WebSocketManager)
|
||||
webSocketManager
|
||||
|
||||
/**
|
||||
* A shortcut-key => action map.
|
||||
*
|
||||
* @protected
|
||||
* @type {?Object.<string, function (KeyboardEvent): void>}
|
||||
*/
|
||||
shortcutKeys = {
|
||||
/** @this CalendarPage */
|
||||
'Home': function (e) {
|
||||
this.handleShortcutKeyHome(e);
|
||||
},
|
||||
/** @this CalendarPage */
|
||||
'Numpad7': function (e) {
|
||||
this.handleShortcutKeyHome(e);
|
||||
},
|
||||
/** @this CalendarPage */
|
||||
'Numpad4': function (e) {
|
||||
this.handleShortcutKeyArrowLeft(e);
|
||||
},
|
||||
/** @this CalendarPage */
|
||||
'Numpad6': function (e) {
|
||||
this.handleShortcutKeyArrowRight(e);
|
||||
},
|
||||
/** @this CalendarPage */
|
||||
'ArrowLeft': function (e) {
|
||||
this.handleShortcutKeyArrowLeft(e);
|
||||
},
|
||||
/** @this CalendarPage */
|
||||
'ArrowRight': function (e) {
|
||||
this.handleShortcutKeyArrowRight(e);
|
||||
},
|
||||
/** @this CalendarPage */
|
||||
'Control+ArrowLeft': function (e) {
|
||||
this.handleShortcutKeyArrowLeft(e);
|
||||
},
|
||||
/** @this CalendarPage */
|
||||
'Control+ArrowRight': function (e) {
|
||||
this.handleShortcutKeyArrowRight(e);
|
||||
},
|
||||
/** @this CalendarPage */
|
||||
'Minus': function (e) {
|
||||
this.handleShortcutKeyMinus(e);
|
||||
},
|
||||
/** @this CalendarPage */
|
||||
'Equal': function (e) {
|
||||
this.handleShortcutKeyPlus(e);
|
||||
},
|
||||
/** @this CalendarPage */
|
||||
'NumpadSubtract': function (e) {
|
||||
this.handleShortcutKeyMinus(e);
|
||||
},
|
||||
/** @this CalendarPage */
|
||||
'NumpadAdd': function (e) {
|
||||
this.handleShortcutKeyPlus(e);
|
||||
},
|
||||
/** @this CalendarPage */
|
||||
'Digit1': function (e) {
|
||||
this.handleShortcutKeyDigit(e, 1);
|
||||
},
|
||||
/** @this CalendarPage */
|
||||
'Digit2': function (e) {
|
||||
this.handleShortcutKeyDigit(e, 2);
|
||||
},
|
||||
/** @this CalendarPage */
|
||||
'Digit3': function (e) {
|
||||
this.handleShortcutKeyDigit(e, 3);
|
||||
},
|
||||
/** @this CalendarPage */
|
||||
'Digit4': function (e) {
|
||||
this.handleShortcutKeyDigit(e, 4);
|
||||
},
|
||||
/** @this CalendarPage */
|
||||
'Digit5': function (e) {
|
||||
this.handleShortcutKeyDigit(e, 5);
|
||||
},
|
||||
/** @this CalendarPage */
|
||||
'Digit6': function (e) {
|
||||
this.handleShortcutKeyDigit(e, 6);
|
||||
},
|
||||
/** @this CalendarPage */
|
||||
'Control+Space': function (e) {
|
||||
this.handleShortcutKeyControlSpace(e);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
|
||||
if (!this.mode) {
|
||||
this.mode = this.getStorage().get('state', 'calendarMode') || null;
|
||||
|
||||
if (this.mode && this.mode.indexOf('view-') === 0) {
|
||||
const viewId = this.mode.slice(5);
|
||||
const calendarViewDataList = this.getPreferences().get('calendarViewDataList') || [];
|
||||
let isFound = false;
|
||||
|
||||
calendarViewDataList.forEach(item => {
|
||||
if (item.id === viewId) {
|
||||
isFound = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (!isFound) {
|
||||
this.mode = null;
|
||||
}
|
||||
|
||||
if (this.options.userId) {
|
||||
this.mode = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.shortcutManager.add(this, this.shortcutKeys);
|
||||
|
||||
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') {
|
||||
this.setupTimeline();
|
||||
}
|
||||
this.initWebSocket();
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
initWebSocket() {
|
||||
if (this.options.userId && this.getUser().id !== this.options.userId) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.webSocketDebounceHelper = new DebounceHelper({
|
||||
interval: this.webSocketDebounceInterval,
|
||||
blockInterval: this.webSocketBlockInterval,
|
||||
handler: () => this.handleWebSocketUpdate(),
|
||||
});
|
||||
|
||||
if (!this.webSocketManager.isEnabled()) {
|
||||
const testHandler = () => this.webSocketDebounceHelper.process();
|
||||
|
||||
this.on('remove', () => window.removeEventListener('calendar-update', testHandler));
|
||||
|
||||
// For testing purpose.
|
||||
window.addEventListener('calendar-update', testHandler);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.webSocketManager.subscribe('calendarUpdate', () => this.webSocketDebounceHelper.process());
|
||||
|
||||
this.on('remove', () => this.webSocketManager.unsubscribe('calendarUpdate'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
handleWebSocketUpdate() {
|
||||
this.getCalendarView()?.actionRefresh({suppressLoadingAlert: true});
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
onSave() {
|
||||
if (!this.webSocketDebounceHelper) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.webSocketDebounceHelper.block()
|
||||
}
|
||||
|
||||
afterRender() {
|
||||
this.$el.focus();
|
||||
}
|
||||
|
||||
updateUrl(trigger) {
|
||||
let url = '#Calendar/show';
|
||||
|
||||
if (this.mode || this.date) {
|
||||
url += '/';
|
||||
}
|
||||
|
||||
if (this.mode) {
|
||||
url += 'mode=' + this.mode;
|
||||
}
|
||||
|
||||
if (this.date) {
|
||||
url += '&date=' + this.date;
|
||||
}
|
||||
|
||||
if (this.options.userId) {
|
||||
url += '&userId=' + this.options.userId;
|
||||
|
||||
if (this.options.userName) {
|
||||
url += '&userName=' + encodeURIComponent(this.options.userName);
|
||||
}
|
||||
}
|
||||
|
||||
this.getRouter().navigate(url, {trigger: trigger});
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
setupCalendar() {
|
||||
const viewName = this.getMetadata().get(['clientDefs', 'Calendar', 'calendarView']) ||
|
||||
'crm:views/calendar/calendar';
|
||||
|
||||
this.createView('calendar', viewName, {
|
||||
date: this.date,
|
||||
userId: this.options.userId,
|
||||
userName: this.options.userName,
|
||||
mode: this.mode,
|
||||
fullSelector: '#main > .calendar-container',
|
||||
onSave: () => this.onSave(),
|
||||
}, view => {
|
||||
let initial = true;
|
||||
|
||||
this.listenTo(view, 'view', (date, mode) => {
|
||||
this.date = date;
|
||||
this.mode = mode;
|
||||
|
||||
if (!initial) {
|
||||
this.updateUrl();
|
||||
}
|
||||
|
||||
initial = false;
|
||||
});
|
||||
|
||||
this.listenTo(view, 'change:mode', (mode, refresh) => {
|
||||
this.mode = mode;
|
||||
|
||||
if (!this.options.userId) {
|
||||
this.getStorage().set('state', 'calendarMode', mode);
|
||||
}
|
||||
|
||||
if (refresh) {
|
||||
this.updateUrl(true);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!~this.fullCalendarModeList.indexOf(mode)) {
|
||||
this.updateUrl(true);
|
||||
}
|
||||
|
||||
this.$el.focus();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
setupTimeline() {
|
||||
const viewName = this.getMetadata().get(['clientDefs', 'Calendar', 'timelineView']) ||
|
||||
'crm:views/calendar/timeline';
|
||||
|
||||
this.createView('calendar', viewName, {
|
||||
date: this.date,
|
||||
userId: this.options.userId,
|
||||
userName: this.options.userName,
|
||||
fullSelector: '#main > .calendar-container',
|
||||
onSave: () => this.onSave(),
|
||||
}, view => {
|
||||
let initial = true;
|
||||
|
||||
this.listenTo(view, 'view', (date, mode) => {
|
||||
this.date = date;
|
||||
this.mode = mode;
|
||||
|
||||
if (!initial) {
|
||||
this.updateUrl();
|
||||
}
|
||||
|
||||
initial = false;
|
||||
});
|
||||
|
||||
this.listenTo(view, 'change:mode', mode => {
|
||||
this.mode = mode;
|
||||
|
||||
if (!this.options.userId) {
|
||||
this.getStorage().set('state', 'calendarMode', mode);
|
||||
}
|
||||
|
||||
this.updateUrl(true);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
updatePageTitle() {
|
||||
this.setPageTitle(this.translate('Calendar', 'scopeNames'));
|
||||
}
|
||||
|
||||
async createCustomView() {
|
||||
const view = new CalendarEditViewModal({
|
||||
afterSave: data => {
|
||||
this.mode = `view-${data.id}`;
|
||||
this.date = null;
|
||||
|
||||
this.updateUrl(true);
|
||||
},
|
||||
});
|
||||
|
||||
await this.assignView('modal', view);
|
||||
|
||||
await view.render();
|
||||
}
|
||||
|
||||
async editCustomView() {
|
||||
const viewId = this.getCalendarView().viewId;
|
||||
|
||||
if (!viewId) {
|
||||
return;
|
||||
}
|
||||
const view = new CalendarEditViewModal({
|
||||
id: viewId,
|
||||
afterSave: () => {
|
||||
this.getCalendarView().setupMode();
|
||||
this.getCalendarView().reRender();
|
||||
},
|
||||
afterRemove: () => {
|
||||
this.mode = null;
|
||||
this.date = null;
|
||||
|
||||
this.updateUrl(true);
|
||||
},
|
||||
});
|
||||
|
||||
await this.assignView('modal', view);
|
||||
|
||||
await view.render();
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @return {import('./calendar').default|import('./timeline').default}
|
||||
*/
|
||||
getCalendarView() {
|
||||
return this.getView('calendar');
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {KeyboardEvent} e
|
||||
*/
|
||||
handleShortcutKeyHome(e) {
|
||||
if (Utils.isKeyEventInTextInput(e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
this.getCalendarView().actionToday();
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {KeyboardEvent} e
|
||||
*/
|
||||
handleShortcutKeyArrowLeft(e) {
|
||||
if (Utils.isKeyEventInTextInput(e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
e.target instanceof HTMLElement &&
|
||||
e.target.parentElement instanceof HTMLLIElement
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
this.getCalendarView().actionPrevious();
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {KeyboardEvent} e
|
||||
*/
|
||||
handleShortcutKeyArrowRight(e) {
|
||||
if (Utils.isKeyEventInTextInput(e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
e.target instanceof HTMLElement &&
|
||||
e.target.parentElement instanceof HTMLLIElement
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
this.getCalendarView().actionNext();
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {KeyboardEvent} e
|
||||
*/
|
||||
handleShortcutKeyMinus(e) {
|
||||
if (Utils.isKeyEventInTextInput(e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.getCalendarView().actionZoomOut) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
this.getCalendarView().actionZoomOut();
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {KeyboardEvent} e
|
||||
*/
|
||||
handleShortcutKeyPlus(e) {
|
||||
if (Utils.isKeyEventInTextInput(e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.getCalendarView().actionZoomIn) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
this.getCalendarView().actionZoomIn();
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {KeyboardEvent} e
|
||||
* @param {Number} digit
|
||||
*/
|
||||
handleShortcutKeyDigit(e, digit) {
|
||||
if (Utils.isKeyEventInTextInput(e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const modeList = this.getCalendarView().hasView('modeButtons') ?
|
||||
this.getCalendarView()
|
||||
.getModeButtonsView()
|
||||
.getModeDataList(true)
|
||||
.map(item => item.mode) :
|
||||
this.getCalendarView().modeList;
|
||||
|
||||
const mode = modeList[digit - 1];
|
||||
|
||||
if (!mode) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
if (mode === this.mode) {
|
||||
this.getCalendarView().actionRefresh();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.getCalendarView().selectMode(mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {KeyboardEvent} e
|
||||
*/
|
||||
handleShortcutKeyControlSpace(e) {
|
||||
if (Utils.isKeyEventInTextInput(e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.getCalendarView().createEvent) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
this.getCalendarView().createEvent();
|
||||
}
|
||||
}
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
export default CalendarPage;
|
||||
1567
client/modules/crm/src/views/calendar/calendar.js
Normal file
1567
client/modules/crm/src/views/calendar/calendar.js
Normal file
File diff suppressed because it is too large
Load Diff
40
client/modules/crm/src/views/calendar/fields/teams.js
Normal file
40
client/modules/crm/src/views/calendar/fields/teams.js
Normal file
@@ -0,0 +1,40 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import LinkMultipleFieldView from 'views/fields/link-multiple';
|
||||
|
||||
export default class CalendarSharedViewTeamsFieldView extends LinkMultipleFieldView {
|
||||
|
||||
foreignScope = 'Team'
|
||||
|
||||
getSelectBoolFilterList() {
|
||||
if (this.getAcl().getPermissionLevel('userCalendar') === 'team') {
|
||||
return ['onlyMy'];
|
||||
}
|
||||
}
|
||||
}
|
||||
47
client/modules/crm/src/views/calendar/fields/users.js
Normal file
47
client/modules/crm/src/views/calendar/fields/users.js
Normal file
@@ -0,0 +1,47 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import LinkMultipleFieldView from 'views/fields/link-multiple';
|
||||
|
||||
class CalendarUsersFieldView extends LinkMultipleFieldView {
|
||||
|
||||
foreignScope = 'User'
|
||||
sortable = true
|
||||
|
||||
getSelectBoolFilterList() {
|
||||
if (this.getAcl().getPermissionLevel('userCalendar') === 'team') {
|
||||
return ['onlyMyTeam'];
|
||||
}
|
||||
}
|
||||
|
||||
getSelectPrimaryFilterName() {
|
||||
return 'active';
|
||||
}
|
||||
}
|
||||
|
||||
export default CalendarUsersFieldView;
|
||||
299
client/modules/crm/src/views/calendar/modals/edit-view.js
Normal file
299
client/modules/crm/src/views/calendar/modals/edit-view.js
Normal file
@@ -0,0 +1,299 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import ModalView from 'views/modal';
|
||||
import Model from 'model';
|
||||
import EditForModalRecordView from 'views/record/edit-for-modal';
|
||||
import EnumFieldView from 'views/fields/enum';
|
||||
import VarcharFieldView from 'views/fields/varchar';
|
||||
import CalendarSharedViewTeamsFieldView from 'crm:views/calendar/fields/teams';
|
||||
|
||||
export default class CalendarEditViewModal extends ModalView {
|
||||
|
||||
// language=Handlebars
|
||||
templateContent = `
|
||||
<div class="record-container no-side-margin">{{{record}}}</div>
|
||||
`
|
||||
|
||||
className = 'dialog dialog-record'
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {EditForModalRecordView}
|
||||
*/
|
||||
recordView
|
||||
|
||||
/**
|
||||
* @param {{
|
||||
* afterSave?: function({id: string}): void,
|
||||
* afterRemove?: function(): void,
|
||||
* id?: string,
|
||||
* }} options
|
||||
*/
|
||||
constructor(options) {
|
||||
super();
|
||||
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
setup() {
|
||||
const id = this.options.id;
|
||||
|
||||
this.buttonList = [
|
||||
{
|
||||
name: 'cancel',
|
||||
label: 'Cancel',
|
||||
onClick: () => this.actionCancel(),
|
||||
},
|
||||
];
|
||||
|
||||
this.isNew = !id;
|
||||
|
||||
const calendarViewDataList = this.getPreferences().get('calendarViewDataList') || [];
|
||||
|
||||
if (this.isNew) {
|
||||
this.buttonList.unshift({
|
||||
name: 'save',
|
||||
label: 'Create',
|
||||
style: 'danger',
|
||||
onClick: () => this.actionSave(),
|
||||
});
|
||||
} else {
|
||||
this.dropdownItemList.push({
|
||||
name: 'remove',
|
||||
label: 'Remove',
|
||||
onClick: () => this.actionRemove(),
|
||||
});
|
||||
|
||||
this.buttonList.unshift({
|
||||
name: 'save',
|
||||
label: 'Save',
|
||||
style: 'primary',
|
||||
onClick: () => this.actionSave(),
|
||||
});
|
||||
}
|
||||
|
||||
const model = new Model();
|
||||
|
||||
model.name = 'CalendarView';
|
||||
|
||||
const modelData = {};
|
||||
|
||||
if (!this.isNew) {
|
||||
calendarViewDataList.forEach(item => {
|
||||
if (id === item.id) {
|
||||
modelData.teamsIds = item.teamIdList || [];
|
||||
modelData.teamsNames = item.teamNames || {};
|
||||
modelData.id = item.id;
|
||||
modelData.name = item.name;
|
||||
modelData.mode = item.mode;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
modelData.name = this.translate('Shared', 'labels', 'Calendar');
|
||||
|
||||
let foundCount = 0;
|
||||
|
||||
calendarViewDataList.forEach(item => {
|
||||
if (item.name.indexOf(modelData.name) === 0) {
|
||||
foundCount++;
|
||||
}
|
||||
});
|
||||
|
||||
if (foundCount) {
|
||||
modelData.name += ' ' + foundCount;
|
||||
}
|
||||
|
||||
modelData.id = id;
|
||||
|
||||
modelData.teamsIds = this.getUser().get('teamsIds') || [];
|
||||
modelData.teamsNames = this.getUser().get('teamsNames') || {};
|
||||
}
|
||||
|
||||
model.set(modelData);
|
||||
|
||||
this.recordView = new EditForModalRecordView({
|
||||
model: model,
|
||||
detailLayout: [
|
||||
{
|
||||
rows: [
|
||||
[
|
||||
{
|
||||
view: new VarcharFieldView({
|
||||
name: 'name',
|
||||
labelText: this.translate('name', 'fields'),
|
||||
params: {
|
||||
required: true,
|
||||
},
|
||||
})
|
||||
},
|
||||
{
|
||||
view: new EnumFieldView({
|
||||
name: 'mode',
|
||||
labelText: this.translate('mode', 'fields', 'DashletOptions'),
|
||||
params: {
|
||||
translation: 'DashletOptions.options.mode',
|
||||
options: this.getMetadata().get('clientDefs.Calendar.sharedViewModeList') || [],
|
||||
},
|
||||
})
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
view: new CalendarSharedViewTeamsFieldView({
|
||||
name: 'teams',
|
||||
labelText: this.translate('teams', 'fields'),
|
||||
params: {
|
||||
required: true
|
||||
},
|
||||
})
|
||||
},
|
||||
false
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
this.assignView('record', this.recordView);
|
||||
|
||||
if (this.isNew) {
|
||||
this.headerText = this.translate('Create Shared View', 'labels', 'Calendar');
|
||||
} else {
|
||||
this.headerText = this.translate('Edit Shared View', 'labels', 'Calendar') + ' · ' +
|
||||
modelData.name;
|
||||
}
|
||||
}
|
||||
|
||||
async actionSave() {
|
||||
if (this.recordView.validate()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const modelData = this.recordView.fetch();
|
||||
|
||||
const calendarViewDataList = this.getPreferences().get('calendarViewDataList') || [];
|
||||
|
||||
const data = {
|
||||
name: modelData.name,
|
||||
teamIdList: modelData.teamsIds,
|
||||
teamNames: modelData.teamsNames,
|
||||
mode: modelData.mode,
|
||||
id: undefined,
|
||||
};
|
||||
|
||||
if (this.isNew) {
|
||||
data.id = Math.random().toString(36).substring(2, 12);
|
||||
|
||||
calendarViewDataList.push(data);
|
||||
} else {
|
||||
data.id = this.getView('record').model.id;
|
||||
|
||||
calendarViewDataList.forEach((item, i) => {
|
||||
if (item.id === data.id) {
|
||||
calendarViewDataList[i] = data;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Espo.Ui.notify(this.translate('saving', 'messages'));
|
||||
|
||||
this.disableButton('save');
|
||||
this.disableButton('remove');
|
||||
|
||||
try {
|
||||
await this.getPreferences().save(
|
||||
{
|
||||
calendarViewDataList: calendarViewDataList,
|
||||
},
|
||||
{patch: true}
|
||||
)
|
||||
} catch (e) {
|
||||
this.enableButton('remove');
|
||||
this.enableButton('save');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Espo.Ui.notify();
|
||||
|
||||
this.trigger('after:save', data);
|
||||
|
||||
if (this.options.afterSave) {
|
||||
this.options.afterSave(data);
|
||||
}
|
||||
|
||||
this.close();
|
||||
}
|
||||
|
||||
async actionRemove() {
|
||||
await this.confirm(this.translate('confirmation', 'messages'));
|
||||
|
||||
this.disableButton('save');
|
||||
this.disableButton('remove');
|
||||
|
||||
const id = this.options.id;
|
||||
|
||||
if (!id) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newCalendarViewDataList = [];
|
||||
|
||||
const calendarViewDataList = this.getPreferences().get('calendarViewDataList') || [];
|
||||
|
||||
calendarViewDataList.forEach(item => {
|
||||
if (item.id !== id) {
|
||||
newCalendarViewDataList.push(item);
|
||||
}
|
||||
});
|
||||
|
||||
Espo.Ui.notifyWait();
|
||||
|
||||
try {
|
||||
await this.getPreferences().save({
|
||||
calendarViewDataList: newCalendarViewDataList,
|
||||
}, {patch: true})
|
||||
} catch (e) {
|
||||
this.enableButton('remove');
|
||||
this.enableButton('save');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Espo.Ui.notify();
|
||||
|
||||
this.trigger('after:remove');
|
||||
|
||||
if (this.options.afterRemove) {
|
||||
this.options.afterRemove();
|
||||
}
|
||||
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
280
client/modules/crm/src/views/calendar/modals/edit.js
Normal file
280
client/modules/crm/src/views/calendar/modals/edit.js
Normal file
@@ -0,0 +1,280 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import EditModalView from 'views/modals/edit';
|
||||
|
||||
class CalenderEditModalView extends EditModalView {
|
||||
|
||||
template = 'crm:calendar/modals/edit'
|
||||
|
||||
scopeList = [
|
||||
'Meeting',
|
||||
'Call',
|
||||
'Task',
|
||||
]
|
||||
|
||||
data() {
|
||||
return {
|
||||
scopeList: this.scopeList,
|
||||
scope: this.scope,
|
||||
isNew: !(this.id),
|
||||
};
|
||||
}
|
||||
|
||||
additionalEvents = {
|
||||
/** @this CalenderEditModalView */
|
||||
'change .scope-switcher input[name="scope"]': function () {
|
||||
Espo.Ui.notifyWait();
|
||||
|
||||
const prevScope = this.scope;
|
||||
|
||||
const scope = $('.scope-switcher input[name="scope"]:checked').val();
|
||||
this.scope = scope;
|
||||
|
||||
this.getModelFactory().create(this.scope, model => {
|
||||
model.populateDefaults();
|
||||
|
||||
let attributes = this.getRecordView().fetch();
|
||||
|
||||
attributes = {...attributes, ...this.getRecordView().model.getClonedAttributes()};
|
||||
|
||||
this.filterAttributesForEntityType(attributes, scope, prevScope);
|
||||
|
||||
model.set(attributes);
|
||||
|
||||
this.model = model;
|
||||
|
||||
this.createRecordView(model, (view) => {
|
||||
view.render();
|
||||
view.notify(false);
|
||||
});
|
||||
|
||||
this.handleAccess(model);
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Record} attributes
|
||||
* @param {string} entityType
|
||||
* @param {string} previousEntityType
|
||||
*/
|
||||
filterAttributesForEntityType(attributes, entityType, previousEntityType) {
|
||||
if (entityType === 'Task' || previousEntityType === 'Task') {
|
||||
delete attributes.reminders;
|
||||
}
|
||||
|
||||
this.getHelper()
|
||||
.fieldManager
|
||||
.getEntityTypeFieldList(entityType, {type: 'enum'})
|
||||
.forEach(field => {
|
||||
if (!(field in attributes)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const options = this.getMetadata().get(['entityDefs', entityType, 'fields', field, 'options']) || [];
|
||||
|
||||
const value = attributes[field];
|
||||
|
||||
if (!~options.indexOf(value)) {
|
||||
delete attributes[field];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
createRecordView(model, callback) {
|
||||
if (!this.id && !this.dateIsChanged) {
|
||||
if (this.options.dateStart && this.options.dateEnd) {
|
||||
this.model.set('dateStart', this.options.dateStart);
|
||||
this.model.set('dateEnd', this.options.dateEnd);
|
||||
}
|
||||
|
||||
if (this.options.allDay) {
|
||||
const allDayScopeList = this.getMetadata().get('clientDefs.Calendar.allDayScopeList') || [];
|
||||
|
||||
if (~allDayScopeList.indexOf(this.scope)) {
|
||||
this.model.set('dateStart', null);
|
||||
this.model.set('dateEnd', null);
|
||||
this.model.set('dateStartDate', null);
|
||||
this.model.set('dateEndDate', this.options.dateEndDate);
|
||||
|
||||
if (this.options.dateEndDate !== this.options.dateStartDate) {
|
||||
this.model.set('dateStartDate', this.options.dateStartDate);
|
||||
}
|
||||
}
|
||||
else if (this.getMetadata().get(['entityDefs', this.scope, 'fields', 'dateStartDate'])) {
|
||||
this.model.set('dateStart', null);
|
||||
this.model.set('dateEnd', null);
|
||||
this.model.set('dateStartDate', this.options.dateStartDate);
|
||||
this.model.set('dateEndDate', this.options.dateEndDate);
|
||||
this.model.set('isAllDay', true);
|
||||
}
|
||||
else {
|
||||
this.model.set('isAllDay', false);
|
||||
this.model.set('dateStartDate', null);
|
||||
this.model.set('dateEndDate', null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.listenTo(this.model, 'change:dateStart', (m, value, o) => {
|
||||
if (o.ui) {
|
||||
this.dateIsChanged = true;
|
||||
}
|
||||
});
|
||||
|
||||
this.listenTo(this.model, 'change:dateEnd', (m, value, o) => {
|
||||
if (o.ui || o.updatedByDuration) {
|
||||
this.dateIsChanged = true;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
super.createRecordView(model, callback);
|
||||
}
|
||||
|
||||
handleAccess(model) {
|
||||
if (
|
||||
this.id &&
|
||||
!this.getAcl().checkModel(model, 'edit') || !this.id &&
|
||||
!this.getAcl().checkModel(model, 'create')
|
||||
) {
|
||||
this.hideButton('save');
|
||||
this.hideButton('fullForm');
|
||||
|
||||
this.$el.find('button[data-name="save"]').addClass('hidden');
|
||||
this.$el.find('button[data-name="fullForm"]').addClass('hidden');
|
||||
}
|
||||
else {
|
||||
this.showButton('save');
|
||||
this.showButton('fullForm');
|
||||
}
|
||||
|
||||
if (!this.getAcl().checkModel(model, 'delete')) {
|
||||
this.hideButton('remove');
|
||||
} else {
|
||||
this.showButton('remove');
|
||||
}
|
||||
}
|
||||
|
||||
afterRender() {
|
||||
super.afterRender();
|
||||
|
||||
if (this.hasView('edit')) {
|
||||
const model = this.getView('edit').model;
|
||||
|
||||
if (model) {
|
||||
this.handleAccess(model);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setup() {
|
||||
this.events = {
|
||||
...this.additionalEvents,
|
||||
...this.events,
|
||||
};
|
||||
|
||||
this.scopeList = Espo.Utils.clone(this.options.scopeList || this.scopeList);
|
||||
this.enabledScopeList = this.options.enabledScopeList || this.scopeList;
|
||||
|
||||
if (!this.options.id && !this.options.scope) {
|
||||
const scopeList = [];
|
||||
|
||||
this.scopeList.forEach((scope) => {
|
||||
if (this.getAcl().check(scope, 'create')) {
|
||||
if (~this.enabledScopeList.indexOf(scope)) {
|
||||
scopeList.push(scope);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.scopeList = scopeList;
|
||||
|
||||
const calendarDefaultEntity = scopeList[0];
|
||||
|
||||
if (calendarDefaultEntity && ~this.scopeList.indexOf(calendarDefaultEntity)) {
|
||||
this.options.scope = calendarDefaultEntity;
|
||||
} else {
|
||||
this.options.scope = this.scopeList[0] || null;
|
||||
}
|
||||
|
||||
if (this.scopeList.length === 0) {
|
||||
this.remove();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
super.setup();
|
||||
|
||||
if (!this.id) {
|
||||
this.$header = $('<a>')
|
||||
.attr('title', this.translate('Full Form'))
|
||||
.attr('role', 'button')
|
||||
.attr('data-action', 'fullForm')
|
||||
.addClass('action')
|
||||
.text(this.translate('Create', 'labels', 'Calendar'));
|
||||
}
|
||||
|
||||
if (this.id) {
|
||||
this.buttonList.splice(1, 0, {
|
||||
name: 'remove',
|
||||
text: this.translate('Remove'),
|
||||
onClick: () => this.actionRemove(),
|
||||
});
|
||||
}
|
||||
|
||||
this.once('after:save', () => {
|
||||
this.$el.find('.scope-switcher').remove();
|
||||
})
|
||||
}
|
||||
|
||||
actionRemove() {
|
||||
const model = this.getView('edit').model;
|
||||
|
||||
this.confirm(this.translate('removeRecordConfirmation', 'messages'), () => {
|
||||
const $buttons = this.dialog.$el.find('.modal-footer button');
|
||||
|
||||
$buttons.addClass('disabled');
|
||||
|
||||
model.destroy()
|
||||
.then(() => {
|
||||
this.trigger('after:delete', model);
|
||||
|
||||
this.dialog.close();
|
||||
})
|
||||
.catch(() => {
|
||||
$buttons.removeClass('disabled');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
setupActionItems() {}
|
||||
}
|
||||
|
||||
export default CalenderEditModalView;
|
||||
144
client/modules/crm/src/views/calendar/modals/shared-options.js
Normal file
144
client/modules/crm/src/views/calendar/modals/shared-options.js
Normal file
@@ -0,0 +1,144 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import ModalView from 'views/modal';
|
||||
import Model from 'model';
|
||||
import EditForModalRecordView from 'views/record/edit-for-modal';
|
||||
import CalendarUsersFieldView from 'crm:views/calendar/fields/users';
|
||||
|
||||
export default class TimelineSharedOptionsModalView extends ModalView {
|
||||
|
||||
className = 'dialog dialog-record'
|
||||
|
||||
templateContent = `
|
||||
<div class="record-container no-side-margin">{{{record}}}</div>
|
||||
`
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {EditForModalRecordView}
|
||||
*/
|
||||
recordView
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {{
|
||||
* users: {id: string, name: string}[],
|
||||
* onApply: function({
|
||||
* users: {id: string, name: string}[],
|
||||
* }),
|
||||
* }} options
|
||||
*/
|
||||
constructor(options) {
|
||||
super(options);
|
||||
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
setup() {
|
||||
this.buttonList = [
|
||||
{
|
||||
name: 'save',
|
||||
label: 'Save',
|
||||
style: 'primary',
|
||||
onClick: () => this.actionSave(),
|
||||
},
|
||||
{
|
||||
name: 'cancel',
|
||||
label: 'Cancel',
|
||||
onClick: () => this.actionClose(),
|
||||
},
|
||||
];
|
||||
|
||||
this.headerText = this.translate('timeline', 'modes', 'Calendar') + ' · ' +
|
||||
this.translate('Shared Mode Options', 'labels', 'Calendar')
|
||||
|
||||
const users = this.options.users;
|
||||
|
||||
const userIdList = [];
|
||||
const userNames = {};
|
||||
|
||||
users.forEach(item => {
|
||||
userIdList.push(item.id);
|
||||
|
||||
userNames[item.id] = item.name;
|
||||
});
|
||||
|
||||
this.model = new Model({
|
||||
usersIds: userIdList,
|
||||
usersNames: userNames,
|
||||
});
|
||||
|
||||
this.recordView = new EditForModalRecordView({
|
||||
model: this.model,
|
||||
detailLayout: [
|
||||
{
|
||||
rows: [
|
||||
[
|
||||
{
|
||||
view: new CalendarUsersFieldView({
|
||||
name: 'users',
|
||||
}),
|
||||
},
|
||||
false
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
this.assignView('record', this.recordView);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
actionSave() {
|
||||
const data = this.recordView.processFetch();
|
||||
|
||||
if (this.recordView.validate()) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @type {{id: string, name: string}[]} */
|
||||
const users = [];
|
||||
|
||||
const userIds = this.model.attributes.usersIds || [];
|
||||
|
||||
userIds.forEach(id => {
|
||||
users.push({
|
||||
id: id,
|
||||
name: (data.usersNames || {})[id] || id
|
||||
});
|
||||
});
|
||||
|
||||
this.options.onApply({users: users})
|
||||
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
158
client/modules/crm/src/views/calendar/mode-buttons.js
Normal file
158
client/modules/crm/src/views/calendar/mode-buttons.js
Normal file
@@ -0,0 +1,158 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import View from 'view';
|
||||
|
||||
/** @module modules/crm/views/calendar/mode-buttons */
|
||||
|
||||
class CalendarModeButtons extends View {
|
||||
|
||||
template = 'crm:calendar/mode-buttons'
|
||||
|
||||
visibleModeListCount = 3
|
||||
|
||||
data() {
|
||||
const scopeFilterList = Espo.Utils.clone(this.scopeList);
|
||||
scopeFilterList.unshift('all');
|
||||
|
||||
const scopeFilterDataList = [];
|
||||
|
||||
this.scopeList.forEach(scope => {
|
||||
const o = {scope: scope};
|
||||
|
||||
if (!this.getCalendarParentView().enabledScopeList.includes(scope)) {
|
||||
o.disabled = true;
|
||||
}
|
||||
|
||||
scopeFilterDataList.push(o);
|
||||
});
|
||||
|
||||
return {
|
||||
mode: this.mode,
|
||||
visibleModeDataList: this.getVisibleModeDataList(),
|
||||
hiddenModeDataList: this.getHiddenModeDataList(),
|
||||
scopeFilterDataList: scopeFilterDataList,
|
||||
isCustomViewAvailable: this.isCustomViewAvailable,
|
||||
hasMoreItems: this.isCustomViewAvailable,
|
||||
hasWorkingTimeCalendarLink: this.getAcl().checkScope('WorkingTimeCalendar'),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {
|
||||
* import('modules/crm/views/calendar/calendar').default|
|
||||
* import('modules/crm/views/calendar/timeline').default
|
||||
* }
|
||||
*/
|
||||
getCalendarParentView() {
|
||||
// noinspection JSValidateTypes
|
||||
return this.getParentView();
|
||||
}
|
||||
|
||||
setup() {
|
||||
this.isCustomViewAvailable = this.options.isCustomViewAvailable;
|
||||
this.modeList = this.options.modeList;
|
||||
this.scopeList = this.options.scopeList;
|
||||
this.mode = this.options.mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {boolean} [originalOrder]
|
||||
* @return {Object.<string, *>[]}
|
||||
*/
|
||||
getModeDataList(originalOrder) {
|
||||
const list = [];
|
||||
|
||||
this.modeList.forEach(name => {
|
||||
const o = {
|
||||
mode: name,
|
||||
label: this.translate(name, 'modes', 'Calendar'),
|
||||
labelShort: this.translate(name, 'modes', 'Calendar').substring(0, 2),
|
||||
};
|
||||
|
||||
list.push(o);
|
||||
});
|
||||
|
||||
if (this.isCustomViewAvailable) {
|
||||
(this.getPreferences().get('calendarViewDataList') || []).forEach(item => {
|
||||
item = Espo.Utils.clone(item);
|
||||
|
||||
item.mode = 'view-' + item.id;
|
||||
item.label = item.name;
|
||||
item.labelShort = (item.name || '').substring(0, 2);
|
||||
list.push(item);
|
||||
});
|
||||
}
|
||||
|
||||
if (originalOrder) {
|
||||
return list;
|
||||
}
|
||||
|
||||
let currentIndex = -1;
|
||||
|
||||
list.forEach((item, i) => {
|
||||
if (item.mode === this.mode) {
|
||||
currentIndex = i;
|
||||
}
|
||||
});
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
getVisibleModeDataList() {
|
||||
const fullList = this.getModeDataList();
|
||||
|
||||
const current = fullList.find(it => it.mode === this.mode);
|
||||
|
||||
const list = fullList.slice(0, this.visibleModeListCount);
|
||||
|
||||
if (current && !list.find(it => it.mode === this.mode)) {
|
||||
list.push(current);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
getHiddenModeDataList() {
|
||||
const fullList = this.getModeDataList();
|
||||
|
||||
const list = [];
|
||||
|
||||
fullList.forEach((o, i) => {
|
||||
if (i < this.visibleModeListCount) {
|
||||
return;
|
||||
}
|
||||
|
||||
list.push(o);
|
||||
});
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
export default CalendarModeButtons;
|
||||
1136
client/modules/crm/src/views/calendar/timeline.js
Normal file
1136
client/modules/crm/src/views/calendar/timeline.js
Normal file
File diff suppressed because it is too large
Load Diff
31
client/modules/crm/src/views/call/detail.js
Normal file
31
client/modules/crm/src/views/call/detail.js
Normal file
@@ -0,0 +1,31 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import MeetingDetailView from 'modules/crm/views/meeting/detail';
|
||||
|
||||
export default class extends MeetingDetailView {}
|
||||
73
client/modules/crm/src/views/call/fields/contacts.js
Normal file
73
client/modules/crm/src/views/call/fields/contacts.js
Normal file
@@ -0,0 +1,73 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import AttendeesFieldView from 'modules/crm/views/meeting/fields/attendees';
|
||||
|
||||
export default class extends AttendeesFieldView {
|
||||
|
||||
getAttributeList() {
|
||||
return [
|
||||
...super.getAttributeList(),
|
||||
'phoneNumbersMap',
|
||||
]
|
||||
}
|
||||
|
||||
getDetailLinkHtml(id, name) {
|
||||
const html = super.getDetailLinkHtml(id, name);
|
||||
|
||||
const key = this.foreignScope + '_' + id;
|
||||
const phoneNumbersMap = this.model.get('phoneNumbersMap') || {};
|
||||
|
||||
if (!(key in phoneNumbersMap)) {
|
||||
return html;
|
||||
}
|
||||
|
||||
const number = phoneNumbersMap[key];
|
||||
|
||||
const $item = $(html);
|
||||
|
||||
// @todo Format phone number.
|
||||
|
||||
$item
|
||||
.append(
|
||||
' ',
|
||||
$('<span>').addClass('text-muted middle-dot'),
|
||||
' ',
|
||||
$('<a>')
|
||||
.attr('href', 'tel:' + number)
|
||||
.attr('data-phone-number', number)
|
||||
.attr('data-action', 'dial')
|
||||
.addClass('small')
|
||||
.text(number)
|
||||
)
|
||||
|
||||
return $('<div>')
|
||||
.append($item)
|
||||
.get(0).outerHTML;
|
||||
}
|
||||
}
|
||||
96
client/modules/crm/src/views/call/fields/date-start.js
Normal file
96
client/modules/crm/src/views/call/fields/date-start.js
Normal file
@@ -0,0 +1,96 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import DatetimeFieldView from 'views/fields/datetime';
|
||||
import moment from 'moment';
|
||||
|
||||
class DateStartCallFieldView extends DatetimeFieldView {
|
||||
|
||||
setup() {
|
||||
super.setup();
|
||||
|
||||
this.notActualStatusList = [
|
||||
...(this.getMetadata().get(`scopes.${this.entityType}.completedStatusList`) || []),
|
||||
...(this.getMetadata().get(`scopes.${this.entityType}.canceledStatusList`) || []),
|
||||
];
|
||||
}
|
||||
|
||||
getAttributeList() {
|
||||
return [
|
||||
...super.getAttributeList(),
|
||||
'dateEnd',
|
||||
'status',
|
||||
];
|
||||
}
|
||||
|
||||
data() {
|
||||
let style;
|
||||
|
||||
const status = this.model.get('status');
|
||||
|
||||
if (
|
||||
status &&
|
||||
!this.notActualStatusList.includes(status) &&
|
||||
(this.mode === this.MODE_DETAIL || this.mode === this.MODE_LIST)
|
||||
) {
|
||||
if (this.isDateInPast('dateEnd')) {
|
||||
style = 'danger';
|
||||
} else if (this.isDateInPast('dateStart')) {
|
||||
style = 'warning';
|
||||
}
|
||||
}
|
||||
|
||||
// noinspection JSValidateTypes
|
||||
return {
|
||||
...super.data(),
|
||||
style: style,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {string} field
|
||||
* @return {boolean}
|
||||
*/
|
||||
isDateInPast(field) {
|
||||
const value = this.model.get(field);
|
||||
|
||||
if (value) {
|
||||
const d = this.getDateTime().toMoment(value);
|
||||
const now = moment().tz(this.getDateTime().timeZone || 'UTC');
|
||||
|
||||
if (d.unix() < now.unix()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export default DateStartCallFieldView;
|
||||
31
client/modules/crm/src/views/call/fields/leads.js
Normal file
31
client/modules/crm/src/views/call/fields/leads.js
Normal file
@@ -0,0 +1,31 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import ContactsFieldView from 'modules/crm/views/call/fields/contacts';
|
||||
|
||||
export default class extends ContactsFieldView {}
|
||||
109
client/modules/crm/src/views/call/record/detail.js
Normal file
109
client/modules/crm/src/views/call/record/detail.js
Normal file
@@ -0,0 +1,109 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import DetailRecordView from 'views/record/detail';
|
||||
|
||||
export default class extends DetailRecordView {
|
||||
|
||||
duplicateAction = true
|
||||
|
||||
setupActionItems() {
|
||||
super.setupActionItems();
|
||||
|
||||
if (!this.getAcl().checkModel(this.model, 'edit')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const historyStatusList = this.getMetadata().get(`scopes.${this.entityType}.historyStatusList`) || [];
|
||||
|
||||
if (
|
||||
!historyStatusList.includes('Held') ||
|
||||
!historyStatusList.includes('Not Held')
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.dropdownItemList.push({
|
||||
'label': 'Set Held',
|
||||
'name': 'setHeld',
|
||||
onClick: () => this.actionSetHeld(),
|
||||
iconClass: 'fas fa-check',
|
||||
});
|
||||
|
||||
this.dropdownItemList.push({
|
||||
'label': 'Set Not Held',
|
||||
'name': 'setNotHeld',
|
||||
onClick: () => this.actionSetNotHeld(),
|
||||
});
|
||||
|
||||
const control = () => {
|
||||
if (
|
||||
historyStatusList.includes(this.model.attributes.status) ||
|
||||
!this.getAcl().checkModel(this.model, 'edit')
|
||||
) {
|
||||
this.hideActionItem('setHeld');
|
||||
this.hideActionItem('setNotHeld');
|
||||
} else {
|
||||
this.showActionItem('setHeld');
|
||||
this.showActionItem('setNotHeld');
|
||||
}
|
||||
};
|
||||
|
||||
control();
|
||||
|
||||
this.model.onSync({
|
||||
owner: this,
|
||||
callback: () => control(),
|
||||
});
|
||||
}
|
||||
|
||||
manageAccessEdit(second) {
|
||||
super.manageAccessEdit(second);
|
||||
|
||||
if (second) {
|
||||
if (!this.getAcl().checkModel(this.model, 'edit', true)) {
|
||||
this.hideActionItem('setHeld');
|
||||
this.hideActionItem('setNotHeld');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
actionSetHeld() {
|
||||
this.model.save({status: 'Held'}, {patch: true})
|
||||
.then(() => {
|
||||
Espo.Ui.success(this.translate('Saved'));
|
||||
});
|
||||
}
|
||||
|
||||
actionSetNotHeld() {
|
||||
this.model.save({status: 'Not Held'}, {patch: true})
|
||||
.then(() => {
|
||||
Espo.Ui.success(this.translate('Saved'));
|
||||
});
|
||||
}
|
||||
}
|
||||
31
client/modules/crm/src/views/call/record/edit-small.js
Normal file
31
client/modules/crm/src/views/call/record/edit-small.js
Normal file
@@ -0,0 +1,31 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import EditRecordView from 'views/record/edit';
|
||||
|
||||
export default class extends EditRecordView {}
|
||||
42
client/modules/crm/src/views/call/record/list-expanded.js
Normal file
42
client/modules/crm/src/views/call/record/list-expanded.js
Normal file
@@ -0,0 +1,42 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
define('crm:views/call/record/list-expanded', ['views/record/list-expanded', 'crm:views/call/record/list'],
|
||||
function (Dep, List) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
actionSetHeld: function (data) {
|
||||
List.prototype.actionSetHeld.call(this, data);
|
||||
},
|
||||
|
||||
actionSetNotHeld: function (data) {
|
||||
List.prototype.actionSetNotHeld.call(this, data);
|
||||
},
|
||||
});
|
||||
});
|
||||
136
client/modules/crm/src/views/call/record/list.js
Normal file
136
client/modules/crm/src/views/call/record/list.js
Normal file
@@ -0,0 +1,136 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import ListRecordView from 'views/record/list';
|
||||
|
||||
export default class extends ListRecordView {
|
||||
|
||||
rowActionsView = 'modules/crm/views/call/record/row-actions/default'
|
||||
|
||||
setup() {
|
||||
super.setup();
|
||||
|
||||
if (
|
||||
this.getAcl().checkScope(this.entityType, 'edit') &&
|
||||
this.getAcl().checkField(this.entityType, 'status', 'edit')
|
||||
) {
|
||||
this.massActionList.push('setHeld');
|
||||
this.massActionList.push('setNotHeld');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @param {Record} data
|
||||
*/
|
||||
async actionSetHeld(data) {
|
||||
const id = data.id;
|
||||
|
||||
if (!id) {
|
||||
return;
|
||||
}
|
||||
|
||||
const model = this.collection.get(id);
|
||||
|
||||
if (!model) {
|
||||
return;
|
||||
}
|
||||
|
||||
Espo.Ui.notify(this.translate('saving', 'messages'));
|
||||
|
||||
await model.save({status: 'Held'}, {patch: true});
|
||||
|
||||
Espo.Ui.success(this.translate('Saved'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @param {Record} data
|
||||
*/
|
||||
async actionSetNotHeld(data) {
|
||||
const id = data.id;
|
||||
|
||||
if (!id) {
|
||||
return;
|
||||
}
|
||||
|
||||
const model = this.collection.get(id);
|
||||
|
||||
if (!model) {
|
||||
return;
|
||||
}
|
||||
|
||||
Espo.Ui.notify(this.translate('saving', 'messages'));
|
||||
|
||||
await model.save({status: 'Not Held'}, {patch: true});
|
||||
|
||||
Espo.Ui.success(this.translate('Saved'));
|
||||
}
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
async massActionSetHeld() {
|
||||
const data = {};
|
||||
|
||||
data.ids = this.checkedList;
|
||||
|
||||
Espo.Ui.notify(this.translate('saving', 'messages'));
|
||||
|
||||
await Espo.Ajax.postRequest(`${this.collection.entityType}/action/massSetHeld`, data);
|
||||
|
||||
Espo.Ui.success(this.translate('Saved'));
|
||||
|
||||
await this.collection.fetch();
|
||||
|
||||
data.ids.forEach(id => {
|
||||
if (this.collection.get(id)) {
|
||||
this.checkRecord(id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
async massActionSetNotHeld() {
|
||||
const data = {};
|
||||
|
||||
data.ids = this.checkedList;
|
||||
|
||||
Espo.Ui.notify(this.translate('saving', 'messages'));
|
||||
|
||||
await Espo.Ajax.postRequest(`${this.collection.entityType}/action/massSetNotHeld`, data);
|
||||
|
||||
Espo.Ui.success(this.translate('Saved'));
|
||||
|
||||
await this.collection.fetch();
|
||||
|
||||
data.ids.forEach(id => {
|
||||
if (this.collection.get(id)) {
|
||||
this.checkRecord(id);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import DashletMeetingRowActionsView from 'modules/crm/views/meeting/record/row-actions/dashlet';
|
||||
|
||||
export default class extends DashletMeetingRowActionsView {}
|
||||
@@ -0,0 +1,31 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import MeetingDefaultRowActionsView from 'modules/crm/views/meeting/record/row-actions/default';
|
||||
|
||||
export default class extends MeetingDefaultRowActionsView {}
|
||||
102
client/modules/crm/src/views/campaign-log-record/fields/data.js
Normal file
102
client/modules/crm/src/views/campaign-log-record/fields/data.js
Normal file
@@ -0,0 +1,102 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
define('crm:views/campaign-log-record/fields/data', ['views/fields/base'], function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
listTemplate: 'crm:campaign-log-record/fields/data/detail',
|
||||
|
||||
getValueForDisplay: function () {
|
||||
let action = this.model.get('action');
|
||||
|
||||
switch (action) {
|
||||
case 'Sent':
|
||||
case 'Opened':
|
||||
if (
|
||||
this.model.get('objectId') &&
|
||||
this.model.get('objectType') &&
|
||||
this.model.get('objectName')
|
||||
) {
|
||||
return $('<a>')
|
||||
.attr('href', '#' + this.model.get('objectType') + '/view/' + this.model.get('objectId'))
|
||||
.text(this.model.get('objectName'))
|
||||
.get(0).outerHTML;
|
||||
}
|
||||
|
||||
return $('<span>')
|
||||
.text(this.model.get('stringData') || '')
|
||||
.get(0).outerHTML;
|
||||
|
||||
case 'Clicked':
|
||||
if (
|
||||
this.model.get('objectId') &&
|
||||
this.model.get('objectType') &&
|
||||
this.model.get('objectName')
|
||||
) {
|
||||
return $('<a>')
|
||||
.attr('href', '#' + this.model.get('objectType') + '/view/' + this.model.get('objectId'))
|
||||
.text(this.model.get('objectName'))
|
||||
.get(0).outerHTML;
|
||||
}
|
||||
|
||||
return $('<span>')
|
||||
.text(this.model.get('stringData') || '')
|
||||
.get(0).outerHTML;
|
||||
|
||||
case 'Opted Out':
|
||||
return $('<span>')
|
||||
.text(this.model.get('stringData') || '')
|
||||
.addClass('text-danger')
|
||||
.get(0).outerHTML;
|
||||
|
||||
case 'Bounced':
|
||||
let emailAddress = this.model.get('stringData');
|
||||
let type = this.model.get('stringAdditionalData');
|
||||
|
||||
let typeLabel = type === 'Hard' ?
|
||||
this.translate('hard', 'labels', 'Campaign') :
|
||||
this.translate('soft', 'labels', 'Campaign')
|
||||
|
||||
return $('<span>')
|
||||
.append(
|
||||
$('<span>')
|
||||
.addClass('label label-default')
|
||||
.text(typeLabel),
|
||||
' ',
|
||||
$('<s>')
|
||||
.text(emailAddress)
|
||||
.addClass(type === 'Hard' ? 'text-danger' : '')
|
||||
)
|
||||
.get(0).outerHTML;
|
||||
}
|
||||
|
||||
return '';
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,34 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
define('crm:views/campaign-tracking-url/record/edit-small', ['views/record/edit-small'], function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
define('crm:views/campaign-tracking-url/record/edit', ['views/record/edit'], function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
});
|
||||
});
|
||||
31
client/modules/crm/src/views/campaign/detail.js
Normal file
31
client/modules/crm/src/views/campaign/detail.js
Normal file
@@ -0,0 +1,31 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import DetailView from 'views/detail';
|
||||
|
||||
export default class extends DetailView {}
|
||||
@@ -0,0 +1,65 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import IntFieldView from 'views/fields/int';
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
export default class extends IntFieldView {
|
||||
|
||||
setup() {
|
||||
this.percentageField = this.name.substr(0, this.name.length - 5) + 'Percentage';
|
||||
|
||||
super.setup();
|
||||
}
|
||||
|
||||
getAttributeList() {
|
||||
const list = super.getAttributeList();
|
||||
|
||||
if (this.model.hasField(this.percentageField)) {
|
||||
list.push(this.percentageField);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
getValueForDisplay() {
|
||||
const percentageFieldName = this.percentageField;
|
||||
|
||||
let value = this.model.get(this.name);
|
||||
const percentageValue = this.model.get(percentageFieldName);
|
||||
|
||||
if (
|
||||
percentageValue != null &&
|
||||
percentageValue
|
||||
) {
|
||||
value += ' ' + '(' + this.model.get(percentageFieldName) + '%)';
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
47
client/modules/crm/src/views/campaign/fields/template.js
Normal file
47
client/modules/crm/src/views/campaign/fields/template.js
Normal file
@@ -0,0 +1,47 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
define('crm:views/campaign/fields/template', ['views/fields/link'], function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
createDisabled: true,
|
||||
|
||||
getSelectFilters: function () {
|
||||
return {
|
||||
entityType: {
|
||||
type: 'in',
|
||||
attribute: 'entityType',
|
||||
value: [
|
||||
this.getMetadata().get(['entityDefs', 'Campaign', 'fields', this.name, 'targetEntityType'])
|
||||
],
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,87 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
define('crm:views/campaign/modals/mail-merge-pdf', ['views/modal', 'ui/select'],
|
||||
function (Dep, /** module:ui/select */ Select) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
template: 'crm:campaign/modals/mail-merge-pdf',
|
||||
|
||||
data: function () {
|
||||
return {
|
||||
linkList: this.linkList,
|
||||
};
|
||||
},
|
||||
|
||||
setup: function () {
|
||||
Dep.prototype.setup.call(this);
|
||||
|
||||
this.headerText = this.translate('Generate Mail Merge PDF', 'labels', 'Campaign');
|
||||
|
||||
var linkList = ['contacts', 'leads', 'accounts', 'users'];
|
||||
this.linkList = [];
|
||||
|
||||
linkList.forEach(link => {
|
||||
if (!this.model.get(link + 'TemplateId')) {
|
||||
return;
|
||||
}
|
||||
|
||||
let targetEntityType = this.getMetadata()
|
||||
.get(['entityDefs', 'TargetList', 'links', link, 'entity']);
|
||||
|
||||
if (!this.getAcl().checkScope(targetEntityType)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.linkList.push(link);
|
||||
});
|
||||
|
||||
this.buttonList.push({
|
||||
name: 'proceed',
|
||||
label: 'Proceed',
|
||||
style: 'danger'
|
||||
});
|
||||
|
||||
this.buttonList.push({
|
||||
name: 'cancel',
|
||||
label: 'Cancel'
|
||||
});
|
||||
},
|
||||
|
||||
afterRender: function () {
|
||||
Select.init(this.$el.find('.field[data-name="link"] select'));
|
||||
},
|
||||
|
||||
actionProceed: function () {
|
||||
let link = this.$el.find('.field[data-name="link"] select').val();
|
||||
|
||||
this.trigger('proceed', link);
|
||||
},
|
||||
});
|
||||
});
|
||||
98
client/modules/crm/src/views/campaign/record/detail.js
Normal file
98
client/modules/crm/src/views/campaign/record/detail.js
Normal file
@@ -0,0 +1,98 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
define('crm:views/campaign/record/detail', ['views/record/detail'], function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
duplicateAction: true,
|
||||
|
||||
setupActionItems: function () {
|
||||
Dep.prototype.setupActionItems.call(this);
|
||||
this.dropdownItemList.push({
|
||||
'label': 'Generate Mail Merge PDF',
|
||||
'name': 'generateMailMergePdf',
|
||||
'hidden': !this.isMailMergeAvailable()
|
||||
});
|
||||
|
||||
this.listenTo(this.model, 'change', function () {
|
||||
if (this.isMailMergeAvailable()) {
|
||||
this.showActionItem('generateMailMergePdf');
|
||||
} else {
|
||||
this.hideActionItem('generateMailMergePdf');
|
||||
}
|
||||
}, this);
|
||||
},
|
||||
|
||||
afterRender: function () {
|
||||
Dep.prototype.afterRender.call(this);
|
||||
},
|
||||
|
||||
isMailMergeAvailable: function () {
|
||||
if (this.model.get('type') !== 'Mail') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.model.get('targetListsIds') || !this.model.get('targetListsIds').length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
!this.model.get('leadsTemplateId') &&
|
||||
!this.model.get('contactsTemplateId') &&
|
||||
!this.model.get('accountsTemplateId') &&
|
||||
!this.model.get('usersTemplateId')
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
actionGenerateMailMergePdf: function () {
|
||||
this.createView('dialog', 'crm:views/campaign/modals/mail-merge-pdf', {
|
||||
model: this.model,
|
||||
}, function (view) {
|
||||
view.render();
|
||||
|
||||
this.listenToOnce(view, 'proceed', (link) => {
|
||||
this.clearView('dialog');
|
||||
|
||||
Espo.Ui.notifyWait();
|
||||
|
||||
Espo.Ajax.postRequest(`Campaign/${this.model.id}/generateMailMerge`, {link: link})
|
||||
.then(response => {
|
||||
Espo.Ui.notify(false);
|
||||
|
||||
window.open('?entryPoint=download&id=' + response.id, '_blank');
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,97 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import RelationshipPanelView from 'views/record/panels/relationship';
|
||||
import RecordModal from 'helpers/record-modal';
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
export default class CampaignLogRecordsPanelView extends RelationshipPanelView {
|
||||
|
||||
filterList = [
|
||||
"all",
|
||||
"sent",
|
||||
"opened",
|
||||
"optedOut",
|
||||
"bounced",
|
||||
"clicked",
|
||||
"optedIn",
|
||||
"leadCreated",
|
||||
]
|
||||
|
||||
setup() {
|
||||
if (this.getAcl().checkScope('TargetList', 'create')) {
|
||||
this.actionList.push({
|
||||
action: 'createTargetList',
|
||||
label: 'Create Target List',
|
||||
});
|
||||
}
|
||||
|
||||
this.filterList = Espo.Utils.clone(this.filterList);
|
||||
|
||||
if (!this.getConfig().get('massEmailOpenTracking')) {
|
||||
const i = this.filterList.indexOf('opened');
|
||||
|
||||
if (i >= 0) {
|
||||
this.filterList.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
super.setup();
|
||||
}
|
||||
|
||||
actionCreateTargetList() {
|
||||
const attributes = {
|
||||
sourceCampaignId: this.model.id,
|
||||
sourceCampaignName: this.model.attributes.name,
|
||||
};
|
||||
|
||||
if (!this.collection.data.primaryFilter) {
|
||||
attributes.includingActionList = [];
|
||||
} else {
|
||||
const status = Espo.Utils.upperCaseFirst(this.collection.data.primaryFilter)
|
||||
.replace(/([A-Z])/g, ' $1');
|
||||
|
||||
attributes.includingActionList = [status];
|
||||
}
|
||||
|
||||
const helper = new RecordModal();
|
||||
|
||||
helper.showCreate(this, {
|
||||
entityType: 'TargetList',
|
||||
attributes: attributes,
|
||||
fullFormDisabled: true,
|
||||
layoutName: 'createFromCampaignLog',
|
||||
afterSave: () => {
|
||||
Espo.Ui.success(this.translate('Done'));
|
||||
},
|
||||
beforeRender: view => {
|
||||
view.getRecordView().setFieldRequired('includingActionList')
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import SidePanelView from 'views/record/panels/side';
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
export default class extends SidePanelView {
|
||||
|
||||
controlStatsFields() {
|
||||
const type = this.model.attributes.type;
|
||||
|
||||
let fieldList;
|
||||
|
||||
switch (type) {
|
||||
case 'Email':
|
||||
case 'Newsletter':
|
||||
fieldList = [
|
||||
'sentCount',
|
||||
'openedCount',
|
||||
'clickedCount',
|
||||
'optedOutCount',
|
||||
'bouncedCount',
|
||||
'leadCreatedCount',
|
||||
'optedInCount',
|
||||
'revenue',
|
||||
];
|
||||
|
||||
break;
|
||||
|
||||
case 'Informational Email':
|
||||
fieldList = [
|
||||
'sentCount',
|
||||
'bouncedCount',
|
||||
];
|
||||
|
||||
break;
|
||||
|
||||
case 'Web':
|
||||
fieldList = ['leadCreatedCount', 'optedInCount', 'revenue'];
|
||||
|
||||
break;
|
||||
|
||||
case 'Television':
|
||||
case 'Radio':
|
||||
fieldList = ['leadCreatedCount', 'revenue'];
|
||||
|
||||
break;
|
||||
|
||||
case 'Mail':
|
||||
fieldList = ['sentCount', 'leadCreatedCount', 'optedInCount', 'revenue'];
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
fieldList = ['leadCreatedCount', 'revenue'];
|
||||
}
|
||||
|
||||
if (!this.getConfig().get('massEmailOpenTracking')) {
|
||||
const i = fieldList.indexOf('openedCount');
|
||||
|
||||
if (i > -1) {
|
||||
fieldList.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
this.statsFieldList.forEach(item => {
|
||||
this.options.recordViewObject.hideField(item);
|
||||
});
|
||||
|
||||
fieldList.forEach(item => {
|
||||
this.options.recordViewObject.showField(item);
|
||||
});
|
||||
|
||||
if (!this.getAcl().checkScope('Lead')) {
|
||||
this.options.recordViewObject.hideField('leadCreatedCount', true);
|
||||
}
|
||||
|
||||
if (!this.getAcl().checkScope('Opportunity')) {
|
||||
this.options.recordViewObject.hideField('revenue', true);
|
||||
}
|
||||
}
|
||||
|
||||
setupFields() {
|
||||
this.fieldList = [
|
||||
'sentCount',
|
||||
'openedCount',
|
||||
'clickedCount',
|
||||
'optedOutCount',
|
||||
'bouncedCount',
|
||||
'leadCreatedCount',
|
||||
'optedInCount',
|
||||
'revenue',
|
||||
];
|
||||
|
||||
this.statsFieldList = this.fieldList;
|
||||
}
|
||||
|
||||
setup() {
|
||||
super.setup();
|
||||
|
||||
this.controlStatsFields();
|
||||
|
||||
this.listenTo(this.model, 'change:type', () => this.controlStatsFields());
|
||||
}
|
||||
}
|
||||
52
client/modules/crm/src/views/campaign/tracking-url.js
Normal file
52
client/modules/crm/src/views/campaign/tracking-url.js
Normal file
@@ -0,0 +1,52 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import View from 'view';
|
||||
|
||||
export default class extends View {
|
||||
|
||||
// language=Handlebars
|
||||
templateContent = `
|
||||
<div class="container content">
|
||||
<div class="block-center-md">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<div class="complex-text">{{complexText message}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
|
||||
data() {
|
||||
// noinspection JSUnresolvedReference
|
||||
return {
|
||||
message: this.options.message,
|
||||
};
|
||||
}
|
||||
}
|
||||
104
client/modules/crm/src/views/campaign/unsubscribe.js
Normal file
104
client/modules/crm/src/views/campaign/unsubscribe.js
Normal file
@@ -0,0 +1,104 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import View from 'view';
|
||||
|
||||
class CampaignUnsubscribeView extends View {
|
||||
|
||||
template = 'crm:campaign/unsubscribe'
|
||||
|
||||
data() {
|
||||
return {
|
||||
isSubscribed: this.isSubscribed,
|
||||
inProcess: this.inProcess,
|
||||
};
|
||||
}
|
||||
|
||||
setup() {
|
||||
super.setup();
|
||||
|
||||
this.actionData = /** @type {Record} */this.options.actionData;
|
||||
|
||||
this.isSubscribed = this.actionData.isSubscribed;
|
||||
this.inProcess = false;
|
||||
|
||||
const endpointUrl = this.actionData.hash && this.actionData.emailAddress ?
|
||||
`Campaign/unsubscribe/${this.actionData.emailAddress}/${this.actionData.hash}`:
|
||||
`Campaign/unsubscribe/${this.actionData.queueItemId}`;
|
||||
|
||||
this.addActionHandler('subscribe', () => {
|
||||
Espo.Ui.notifyWait();
|
||||
|
||||
this.inProcess = true;
|
||||
this.reRender();
|
||||
|
||||
Espo.Ajax.deleteRequest(endpointUrl)
|
||||
.then(() => {
|
||||
this.isSubscribed = true;
|
||||
this.inProcess = false;
|
||||
|
||||
this.reRender().then(() => {
|
||||
const message = this.translate('subscribedAgain', 'messages', 'Campaign');
|
||||
|
||||
Espo.Ui.notify(message, 'success', 0, {closeButton: true});
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
this.inProcess = false;
|
||||
this.reRender();
|
||||
});
|
||||
});
|
||||
|
||||
this.addActionHandler('unsubscribe', () => {
|
||||
Espo.Ui.notifyWait();
|
||||
|
||||
this.inProcess = true;
|
||||
this.reRender();
|
||||
|
||||
Espo.Ajax.postRequest(endpointUrl)
|
||||
.then(() => {
|
||||
Espo.Ui.success(this.translate('unsubscribed', 'messages', 'Campaign'), {closeButton: true});
|
||||
|
||||
this.isSubscribed = false;
|
||||
this.inProcess = false;
|
||||
|
||||
this.reRender().then(() => {
|
||||
const message = this.translate('unsubscribed', 'messages', 'Campaign');
|
||||
|
||||
Espo.Ui.notify(message, 'success', 0, {closeButton: true});
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
this.inProcess = false;
|
||||
this.reRender();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default CampaignUnsubscribeView;
|
||||
48
client/modules/crm/src/views/case/record/detail.js
Normal file
48
client/modules/crm/src/views/case/record/detail.js
Normal file
@@ -0,0 +1,48 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import DetailRecordView from 'views/record/detail';
|
||||
|
||||
export default class extends DetailRecordView {
|
||||
|
||||
selfAssignAction = true
|
||||
|
||||
getSelfAssignAttributes() {
|
||||
if (this.model.attributes.status === 'New') {
|
||||
const options = this.getMetadata().get(['entityDefs', 'Case', 'fields', 'status', 'options']) || [];
|
||||
|
||||
if (options.includes('Assigned')) {
|
||||
return {
|
||||
status: 'Assigned',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
define('crm:views/case/record/panels/activities', ['crm:views/record/panels/activities'], function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
getComposeEmailAttributes: function (scope, data, callback) {
|
||||
data = data || {};
|
||||
|
||||
Espo.Ui.notifyWait();
|
||||
|
||||
Dep.prototype.getComposeEmailAttributes.call(this, scope, data, attributes => {
|
||||
attributes.name = '[#' + this.model.get('number') + '] ' + this.model.get('name');
|
||||
|
||||
Espo.Ajax.getRequest('Case/action/emailAddressList?id=' + this.model.id).then(list => {
|
||||
attributes.to = '';
|
||||
attributes.cc = '';
|
||||
attributes.nameHash = {};
|
||||
|
||||
list.forEach((item, i) => {
|
||||
if (i === 0) {
|
||||
attributes.to += item.emailAddress + ';';
|
||||
} else {
|
||||
attributes.cc += item.emailAddress + ';';
|
||||
}
|
||||
|
||||
attributes.nameHash[item.emailAddress] = item.name;
|
||||
});
|
||||
|
||||
Espo.Ui.notify(false);
|
||||
|
||||
callback.call(this, attributes);
|
||||
});
|
||||
})
|
||||
},
|
||||
});
|
||||
});
|
||||
32
client/modules/crm/src/views/contact/detail.js
Normal file
32
client/modules/crm/src/views/contact/detail.js
Normal file
@@ -0,0 +1,32 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import DetailView from 'views/detail';
|
||||
|
||||
/** Left for bc. */
|
||||
export default class extends DetailView {}
|
||||
63
client/modules/crm/src/views/contact/fields/account-role.js
Normal file
63
client/modules/crm/src/views/contact/fields/account-role.js
Normal file
@@ -0,0 +1,63 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
define('crm:views/contact/fields/account-role', ['views/fields/varchar'], function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
detailTemplate: 'crm:contact/fields/account-role/detail',
|
||||
listTemplate: 'crm:contact/fields/account-role/detail',
|
||||
|
||||
setup: function () {
|
||||
Dep.prototype.setup.call(this);
|
||||
|
||||
this.listenTo(this.model, 'change:title', () => {
|
||||
this.model.set('accountRole', this.model.get('title'));
|
||||
});
|
||||
},
|
||||
|
||||
getAttributeList: function () {
|
||||
var list = Dep.prototype.getAttributeList.call(this);
|
||||
|
||||
list.push('title');
|
||||
list.push('accountIsInactive');
|
||||
|
||||
return list;
|
||||
},
|
||||
|
||||
data: function () {
|
||||
var data = Dep.prototype.data.call(this);
|
||||
|
||||
if (this.model.has('accountIsInactive')) {
|
||||
data.accountIsInactive = this.model.get('accountIsInactive');
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
});
|
||||
});
|
||||
51
client/modules/crm/src/views/contact/fields/account.js
Normal file
51
client/modules/crm/src/views/contact/fields/account.js
Normal file
@@ -0,0 +1,51 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
define('crm:views/contact/fields/account', ['views/fields/link'], function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
getAttributeList: function () {
|
||||
var list = Dep.prototype.getAttributeList.call(this);
|
||||
|
||||
list.push('accountIsInactive');
|
||||
|
||||
return list;
|
||||
},
|
||||
|
||||
afterRender: function () {
|
||||
Dep.prototype.afterRender.call(this);
|
||||
|
||||
if (this.mode === 'list' || this.mode === 'detail') {
|
||||
if (this.model.get('accountIsInactive')) {
|
||||
this.$el.find('a').css('textDecoration', 'line-through');
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
});
|
||||
239
client/modules/crm/src/views/contact/fields/accounts.js
Normal file
239
client/modules/crm/src/views/contact/fields/accounts.js
Normal file
@@ -0,0 +1,239 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import LinkMultipleWithColumnsFieldView from 'views/fields/link-multiple-with-columns';
|
||||
|
||||
class AccountsFieldView extends LinkMultipleWithColumnsFieldView {
|
||||
|
||||
getAttributeList() {
|
||||
const list = super.getAttributeList();
|
||||
|
||||
list.push('accountId');
|
||||
list.push('accountName');
|
||||
list.push('title');
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
setup() {
|
||||
super.setup();
|
||||
|
||||
this.events['click [data-action="switchPrimary"]'] = e => {
|
||||
const $target = $(e.currentTarget);
|
||||
const id = $target.data('id');
|
||||
|
||||
if (!$target.hasClass('active')) {
|
||||
this.$el.find('button[data-action="switchPrimary"]')
|
||||
.removeClass('active')
|
||||
.children()
|
||||
.addClass('text-muted');
|
||||
|
||||
$target.addClass('active')
|
||||
.children()
|
||||
.removeClass('text-muted');
|
||||
|
||||
this.setPrimaryId(id);
|
||||
}
|
||||
};
|
||||
|
||||
this.primaryIdFieldName = 'accountId';
|
||||
this.primaryNameFieldName = 'accountName';
|
||||
this.primaryRoleFieldName = 'title';
|
||||
|
||||
this.primaryId = this.model.get(this.primaryIdFieldName);
|
||||
this.primaryName = this.model.get(this.primaryNameFieldName);
|
||||
|
||||
this.listenTo(this.model, 'change:' + this.primaryIdFieldName, () => {
|
||||
this.primaryId = this.model.get(this.primaryIdFieldName);
|
||||
this.primaryName = this.model.get(this.primaryNameFieldName);
|
||||
});
|
||||
|
||||
if (this.isEditMode() || this.isDetailMode()) {
|
||||
this.events['click a[data-action="setPrimary"]'] = (e) => {
|
||||
const id = $(e.currentTarget).data('id');
|
||||
|
||||
this.setPrimaryId(id);
|
||||
this.reRender();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setPrimaryId(id) {
|
||||
this.primaryId = id;
|
||||
|
||||
if (id) {
|
||||
this.primaryName = this.nameHash[id];
|
||||
} else {
|
||||
this.primaryName = null;
|
||||
}
|
||||
|
||||
this.trigger('change');
|
||||
}
|
||||
|
||||
renderLinks() {
|
||||
if (this.primaryId) {
|
||||
this.addLinkHtml(this.primaryId, this.primaryName);
|
||||
}
|
||||
|
||||
this.ids.forEach(id => {
|
||||
if (id !== this.primaryId) {
|
||||
this.addLinkHtml(id, this.nameHash[id]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
getValueForDisplay() {
|
||||
if (this.isDetailMode() || this.isListMode()) {
|
||||
const itemList = [];
|
||||
|
||||
if (this.primaryId) {
|
||||
itemList.push(this.getDetailLinkHtml(this.primaryId, this.primaryName));
|
||||
}
|
||||
|
||||
this.ids.forEach(id => {
|
||||
if (id !== this.primaryId) {
|
||||
itemList.push(this.getDetailLinkHtml(id));
|
||||
}
|
||||
});
|
||||
|
||||
return itemList
|
||||
.map(item => {
|
||||
return $('<div>')
|
||||
.addClass('link-multiple-item')
|
||||
.html(item)
|
||||
.get(0).outerHTML;
|
||||
})
|
||||
.join('');
|
||||
}
|
||||
}
|
||||
|
||||
getDetailLinkHtml(id, name) {
|
||||
const html = super.getDetailLinkHtml(id, name);
|
||||
|
||||
if (this.getColumnValue(id, 'isInactive')) {
|
||||
const $el = $('<div>').html(html);
|
||||
|
||||
$el.find('a').css('text-decoration', 'line-through');
|
||||
|
||||
return $el.get(0).innerHTML;
|
||||
}
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
afterAddLink(id) {
|
||||
super.afterAddLink(id);
|
||||
|
||||
if (this.ids.length === 1) {
|
||||
this.primaryId = id;
|
||||
this.primaryName = this.nameHash[id];
|
||||
}
|
||||
|
||||
this.controlPrimaryAppearance();
|
||||
}
|
||||
|
||||
afterDeleteLink(id) {
|
||||
super.afterDeleteLink(id);
|
||||
|
||||
if (this.ids.length === 0) {
|
||||
this.primaryId = null;
|
||||
this.primaryName = null;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (id === this.primaryId) {
|
||||
this.primaryId = this.ids[0];
|
||||
this.primaryName = this.nameHash[this.primaryId];
|
||||
}
|
||||
|
||||
this.controlPrimaryAppearance();
|
||||
}
|
||||
|
||||
controlPrimaryAppearance() {
|
||||
this.$el.find('li.set-primary-list-item').removeClass('hidden');
|
||||
|
||||
if (this.primaryId) {
|
||||
this.$el.find('li.set-primary-list-item[data-id="'+this.primaryId+'"]').addClass('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
addLinkHtml(id, name) {
|
||||
name = name || id;
|
||||
|
||||
if (this.isSearchMode()) {
|
||||
return super.addLinkHtml(id, name);
|
||||
}
|
||||
|
||||
const $el = super.addLinkHtml(id, name);
|
||||
|
||||
const isPrimary = id === this.primaryId;
|
||||
|
||||
const $a = $('<a>')
|
||||
.attr('role', 'button')
|
||||
.attr('tabindex', '0')
|
||||
.attr('data-action', 'setPrimary')
|
||||
.attr('data-id', id)
|
||||
.text(this.translate('Set Primary', 'labels', 'Account'));
|
||||
|
||||
const $li = $('<li>')
|
||||
.addClass('set-primary-list-item')
|
||||
.attr('data-id', id)
|
||||
.append($a);
|
||||
|
||||
if (isPrimary || this.ids.length === 1) {
|
||||
$li.addClass('hidden');
|
||||
}
|
||||
|
||||
$el.find('ul.dropdown-menu').append($li);
|
||||
|
||||
if (this.getColumnValue(id, 'isInactive')) {
|
||||
$el.find('div.link-item-name').css('text-decoration', 'line-through');
|
||||
}
|
||||
}
|
||||
|
||||
fetch() {
|
||||
const data = super.fetch();
|
||||
|
||||
data[this.primaryIdFieldName] = this.primaryId;
|
||||
data[this.primaryNameFieldName] = this.primaryName;
|
||||
data[this.primaryRoleFieldName] = (this.columns[this.primaryId] || {}).role || null;
|
||||
|
||||
// noinspection JSUnresolvedReference
|
||||
data.accountIsInactive = (this.columns[this.primaryId] || {}).isInactive || false;
|
||||
|
||||
if (!this.primaryId) {
|
||||
data[this.primaryRoleFieldName] = null;
|
||||
data.accountIsInactive = null;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
export default AccountsFieldView;
|
||||
@@ -0,0 +1,47 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
define('crm:views/contact/fields/name-for-account', ['views/fields/person-name'], function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
afterRender: function () {
|
||||
Dep.prototype.afterRender.call(this);
|
||||
|
||||
if (this.mode === 'listLink') {
|
||||
if (this.model.get('accountIsInactive')) {
|
||||
this.$el.find('a').css('text-decoration', 'line-through');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getAttributeList: function () {
|
||||
return ['name', 'accountIsInactive'];
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,35 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
define('crm:views/contact/fields/opportunity-role', ['views/fields/enum'], function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
searchTypeList: ['anyOf', 'noneOf'],
|
||||
});
|
||||
});
|
||||
39
client/modules/crm/src/views/contact/fields/title.js
Normal file
39
client/modules/crm/src/views/contact/fields/title.js
Normal file
@@ -0,0 +1,39 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
define('crm:views/contact/fields/title', ['views/fields/varchar'], function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
setupOptions: function () {
|
||||
this.params.options = Espo.Utils.clone(
|
||||
this.getMetadata().get('entityDefs.Account.fields.contactRole.options') || []
|
||||
);
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,60 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import SelectRecordsModalView from 'views/modals/select-records';
|
||||
|
||||
export default class SelectForPortalUserModalView extends SelectRecordsModalView {
|
||||
|
||||
/**
|
||||
* @param {
|
||||
* module:views/modals/select-records~Options &
|
||||
* {onSkip: function()}
|
||||
* } options
|
||||
*/
|
||||
constructor(options) {
|
||||
super(options);
|
||||
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
setup() {
|
||||
super.setup();
|
||||
|
||||
this.buttonList.unshift({
|
||||
name: 'skip',
|
||||
text: this.translate('Proceed w/o Contact', 'labels', 'User'),
|
||||
onClick: () => this.actionSkip(),
|
||||
});
|
||||
}
|
||||
|
||||
actionSkip() {
|
||||
this.options.onSkip();
|
||||
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
34
client/modules/crm/src/views/contact/record/detail-small.js
Normal file
34
client/modules/crm/src/views/contact/record/detail-small.js
Normal file
@@ -0,0 +1,34 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
define('crm:views/contact/record/detail-small', ['views/record/detail-small', 'crm:views/contact/record/detail'], function (Dep, Detail) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
});
|
||||
});
|
||||
32
client/modules/crm/src/views/contact/record/detail.js
Normal file
32
client/modules/crm/src/views/contact/record/detail.js
Normal file
@@ -0,0 +1,32 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
define('crm:views/contact/record/detail', ['views/record/detail'], function (Dep) {
|
||||
|
||||
return Dep.extend({});
|
||||
});
|
||||
320
client/modules/crm/src/views/dashlets/abstract/chart.js
Normal file
320
client/modules/crm/src/views/dashlets/abstract/chart.js
Normal file
@@ -0,0 +1,320 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
define('crm:views/dashlets/abstract/chart', ['views/dashlets/abstract/base','lib!flotr2'], function (Dep, Flotr) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
templateContent: '<div class="chart-container"></div><div class="legend-container"></div>',
|
||||
|
||||
decimalMark: '.',
|
||||
thousandSeparator: ',',
|
||||
|
||||
defaultColorList: ['#6FA8D6', '#4E6CAD', '#EDC555', '#ED8F42', '#DE6666', '#7CC4A4', '#8A7CC2', '#D4729B'],
|
||||
successColor: '#85b75f',
|
||||
gridColor: '#ddd',
|
||||
tickColor: '#e8eced',
|
||||
textColor: '#333',
|
||||
hoverColor: '#FF3F19',
|
||||
legendColumnWidth: 110,
|
||||
legendColumnNumber: 6,
|
||||
|
||||
labelFormatter: function (v) {
|
||||
return '<span style="color:'+this.textColor+'">' + v + '</span>';
|
||||
},
|
||||
|
||||
init: function () {
|
||||
Dep.prototype.init.call(this);
|
||||
|
||||
this.fontSizeFactor = this.getThemeManager().getFontSizeFactor();
|
||||
|
||||
this.flotr = Flotr;
|
||||
|
||||
this.successColor = this.getThemeManager().getParam('chartSuccessColor') || this.successColor;
|
||||
this.colorList = this.getThemeManager().getParam('chartColorList') || this.defaultColorList;
|
||||
this.tickColor = this.getThemeManager().getParam('chartTickColor') || this.tickColor;
|
||||
this.gridColor = this.getThemeManager().getParam('chartGridColor') || this.gridColor;
|
||||
this.textColor = this.getThemeManager().getParam('textColor') || this.textColor;
|
||||
this.hoverColor = this.getThemeManager().getParam('hoverColor') || this.hoverColor;
|
||||
|
||||
if (this.getPreferences().has('decimalMark')) {
|
||||
this.decimalMark = this.getPreferences().get('decimalMark')
|
||||
} else {
|
||||
if (this.getConfig().has('decimalMark')) {
|
||||
this.decimalMark = this.getConfig().get('decimalMark')
|
||||
}
|
||||
}
|
||||
|
||||
if (this.getPreferences().has('thousandSeparator')) {
|
||||
this.thousandSeparator = this.getPreferences().get('thousandSeparator')
|
||||
} else {
|
||||
if (this.getConfig().has('thousandSeparator')) {
|
||||
this.thousandSeparator = this.getConfig().get('thousandSeparator')
|
||||
}
|
||||
}
|
||||
|
||||
this.on('resize', () => {
|
||||
if (!this.isRendered()) {
|
||||
return;
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
this.adjustContainer();
|
||||
|
||||
if (this.isNoData()) {
|
||||
this.showNoData();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.draw();
|
||||
}, 50);
|
||||
});
|
||||
|
||||
$(window).on('resize.chart' + this.id, () => {
|
||||
this.adjustContainer();
|
||||
|
||||
if (this.isNoData()) {
|
||||
this.showNoData();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.draw();
|
||||
});
|
||||
|
||||
this.once('remove', () => {
|
||||
$(window).off('resize.chart' + this.id)
|
||||
});
|
||||
},
|
||||
|
||||
formatNumber: function (value, isCurrency, useSiMultiplier) {
|
||||
if (value !== null) {
|
||||
let maxDecimalPlaces = 2;
|
||||
|
||||
var currencyDecimalPlaces = this.getConfig().get('currencyDecimalPlaces');
|
||||
|
||||
var siSuffix = '';
|
||||
|
||||
if (useSiMultiplier) {
|
||||
if (value >= 1000000) {
|
||||
siSuffix = 'M';
|
||||
value = value / 1000000;
|
||||
} else if (value >= 1000) {
|
||||
siSuffix = 'k';
|
||||
value = value / 1000;
|
||||
}
|
||||
}
|
||||
|
||||
if (isCurrency) {
|
||||
if (currencyDecimalPlaces === 0) {
|
||||
value = Math.round(value);
|
||||
} else if (currencyDecimalPlaces) {
|
||||
value = Math.round(value * Math.pow(10, currencyDecimalPlaces)) /
|
||||
(Math.pow(10, currencyDecimalPlaces));
|
||||
} else {
|
||||
value = Math.round(value * Math.pow(10, maxDecimalPlaces)) / (Math.pow(10, maxDecimalPlaces));
|
||||
}
|
||||
} else {
|
||||
let maxDecimalPlaces = 4;
|
||||
|
||||
if (useSiMultiplier) {
|
||||
maxDecimalPlaces = 2;
|
||||
}
|
||||
|
||||
value = Math.round(value * Math.pow(10, maxDecimalPlaces)) / (Math.pow(10, maxDecimalPlaces));
|
||||
}
|
||||
|
||||
var parts = value.toString().split(".");
|
||||
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, this.thousandSeparator);
|
||||
|
||||
if (isCurrency) {
|
||||
if (currencyDecimalPlaces === 0) {
|
||||
delete parts[1];
|
||||
}
|
||||
else if (currencyDecimalPlaces) {
|
||||
var decimalPartLength = 0;
|
||||
|
||||
if (parts.length > 1) {
|
||||
decimalPartLength = parts[1].length;
|
||||
} else {
|
||||
parts[1] = '';
|
||||
}
|
||||
|
||||
if (currencyDecimalPlaces && decimalPartLength < currencyDecimalPlaces) {
|
||||
var limit = currencyDecimalPlaces - decimalPartLength;
|
||||
|
||||
for (let i = 0; i < limit; i++) {
|
||||
parts[1] += '0';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return parts.join(this.decimalMark) + siSuffix;
|
||||
}
|
||||
|
||||
return '';
|
||||
},
|
||||
|
||||
getLegendColumnNumber: function () {
|
||||
const width = this.$el.closest('.panel-body').width();
|
||||
|
||||
const legendColumnNumber = Math.floor(width / (this.legendColumnWidth * this.fontSizeFactor));
|
||||
|
||||
return legendColumnNumber || this.legendColumnNumber;
|
||||
},
|
||||
|
||||
getLegendHeight: function () {
|
||||
const lineNumber = Math.ceil(this.chartData.length / this.getLegendColumnNumber());
|
||||
let legendHeight = 0;
|
||||
|
||||
const lineHeight = (this.getThemeManager().getParam('dashletChartLegendRowHeight') || 19) *
|
||||
this.fontSizeFactor;
|
||||
|
||||
const paddingTopHeight = (this.getThemeManager().getParam('dashletChartLegendPaddingTopHeight') || 7) *
|
||||
this.fontSizeFactor;
|
||||
|
||||
if (lineNumber > 0) {
|
||||
legendHeight = lineHeight * lineNumber + paddingTopHeight;
|
||||
}
|
||||
|
||||
return legendHeight;
|
||||
},
|
||||
|
||||
adjustContainer: function () {
|
||||
const legendHeight = this.getLegendHeight();
|
||||
const heightCss = `calc(100% - ${legendHeight.toString()}px)`;
|
||||
|
||||
this.$container.css('height', heightCss);
|
||||
},
|
||||
|
||||
adjustLegend: function () {
|
||||
const number = this.getLegendColumnNumber();
|
||||
|
||||
if (!number) {
|
||||
return;
|
||||
}
|
||||
|
||||
const dashletChartLegendBoxWidth = (this.getThemeManager().getParam('dashletChartLegendBoxWidth') || 21) *
|
||||
this.fontSizeFactor;
|
||||
|
||||
const containerWidth = this.$legendContainer.width();
|
||||
const width = Math.floor((containerWidth - dashletChartLegendBoxWidth * number) / number);
|
||||
const columnNumber = this.$legendContainer.find('> table tr:first-child > td').length / 2;
|
||||
|
||||
const tableWidth = (width + dashletChartLegendBoxWidth) * columnNumber;
|
||||
|
||||
this.$legendContainer.find('> table')
|
||||
.css('table-layout', 'fixed')
|
||||
.attr('width', tableWidth);
|
||||
|
||||
this.$legendContainer.find('td.flotr-legend-label').attr('width', width);
|
||||
this.$legendContainer.find('td.flotr-legend-color-box').attr('width', dashletChartLegendBoxWidth);
|
||||
|
||||
this.$legendContainer.find('td.flotr-legend-label > span').each((i, span) => {
|
||||
span.setAttribute('title', span.textContent);
|
||||
});
|
||||
},
|
||||
|
||||
afterRender: function () {
|
||||
this.$el.closest('.panel-body').css({
|
||||
'overflow-y': 'visible',
|
||||
'overflow-x': 'visible',
|
||||
});
|
||||
|
||||
this.$legendContainer = this.$el.find('.legend-container');
|
||||
this.$container = this.$el.find('.chart-container');
|
||||
|
||||
this.fetch(function (data) {
|
||||
this.chartData = this.prepareData(data);
|
||||
|
||||
this.adjustContainer();
|
||||
|
||||
if (this.isNoData()) {
|
||||
this.showNoData();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
if (!this.$container.length || !this.$container.is(":visible")) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.draw();
|
||||
}, 1);
|
||||
});
|
||||
},
|
||||
|
||||
isNoData: function () {
|
||||
return false;
|
||||
},
|
||||
|
||||
url: function () {},
|
||||
|
||||
prepareData: function (response) {
|
||||
return response;
|
||||
},
|
||||
|
||||
fetch: function (callback) {
|
||||
Espo.Ajax.getRequest(this.url())
|
||||
.then(response => {
|
||||
callback.call(this, response);
|
||||
});
|
||||
},
|
||||
|
||||
getDateFilter: function () {
|
||||
return this.getOption('dateFilter') || 'currentYear';
|
||||
},
|
||||
|
||||
showNoData: function () {
|
||||
this.$container.empty();
|
||||
|
||||
const $text = $('<span>').html(this.translate('No Data')).addClass('text-muted');
|
||||
|
||||
const $div = $('<div>')
|
||||
.css('text-align', 'center')
|
||||
.css('font-size', 'calc(var(--font-size-base) * 1.2)')
|
||||
.css('display', 'table')
|
||||
.css('width', '100%')
|
||||
.css('height', '100%')
|
||||
.css('user-select', 'none');
|
||||
|
||||
$text
|
||||
.css('display', 'table-cell')
|
||||
.css('vertical-align', 'middle')
|
||||
.css('padding-bottom', 'calc(var(--font-size-base) * 1.5)');
|
||||
|
||||
|
||||
$div.append($text);
|
||||
|
||||
this.$container.append($div);
|
||||
},
|
||||
});
|
||||
});
|
||||
276
client/modules/crm/src/views/dashlets/activities.js
Normal file
276
client/modules/crm/src/views/dashlets/activities.js
Normal file
@@ -0,0 +1,276 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import BaseDashletView from 'views/dashlets/abstract/base';
|
||||
import MultiCollection from 'multi-collection';
|
||||
import RecordModalHelper from 'helpers/record-modal';
|
||||
|
||||
class ActivitiesDashletView extends BaseDashletView {
|
||||
|
||||
name = 'Activities'
|
||||
|
||||
// language=Handlebars
|
||||
templateContent = '<div class="list-container">{{{list}}}</div>'
|
||||
|
||||
rowActionsView = 'crm:views/record/row-actions/activities-dashlet'
|
||||
|
||||
defaultListLayout = {
|
||||
rows: [
|
||||
[
|
||||
{
|
||||
name: 'ico',
|
||||
view: 'crm:views/fields/ico',
|
||||
params: {
|
||||
notRelationship: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'name',
|
||||
link: true,
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
name: 'dateStart',
|
||||
soft: true
|
||||
},
|
||||
{
|
||||
name: 'parent',
|
||||
},
|
||||
],
|
||||
],
|
||||
}
|
||||
|
||||
listLayoutEntityTypeMap = {
|
||||
Task: {
|
||||
rows: [
|
||||
[
|
||||
{
|
||||
name: 'ico',
|
||||
view: 'crm:views/fields/ico',
|
||||
params: {
|
||||
notRelationship: true
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'name',
|
||||
link: true,
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
name: 'status',
|
||||
},
|
||||
{
|
||||
name: 'dateEnd',
|
||||
soft: true
|
||||
},
|
||||
{
|
||||
name: 'priority',
|
||||
view: 'crm:views/task/fields/priority-for-dashlet',
|
||||
},
|
||||
{
|
||||
name: 'parent',
|
||||
},
|
||||
],
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
setup() {
|
||||
this.seeds = {};
|
||||
|
||||
this.scopeList = this.getOption('enabledScopeList') || [];
|
||||
|
||||
this.listLayout = {};
|
||||
|
||||
this.scopeList.forEach((item) => {
|
||||
if (item in this.listLayoutEntityTypeMap) {
|
||||
this.listLayout[item] = this.listLayoutEntityTypeMap[item];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.listLayout[item] = this.defaultListLayout;
|
||||
});
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
this.scopeList.slice(0).reverse().forEach(scope => {
|
||||
if (this.getAcl().checkScope(scope, 'create')) {
|
||||
this.actionList.unshift({
|
||||
name: 'createActivity',
|
||||
text: this.translate('Create ' + scope, 'labels', scope),
|
||||
iconClass: 'fas fa-plus',
|
||||
url: '#' + scope + '/create',
|
||||
data: {
|
||||
scope: scope,
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
afterRender() {
|
||||
this.collection = new MultiCollection();
|
||||
this.collection.seeds = this.seeds;
|
||||
this.collection.url = 'Activities/upcoming';
|
||||
this.collection.maxSize = this.getOption('displayRecords') ||
|
||||
this.getConfig().get('recordsPerPageSmall') || 5;
|
||||
this.collection.data.entityTypeList = this.scopeList;
|
||||
this.collection.data.futureDays = this.getOption('futureDays');
|
||||
|
||||
if (this.getOption('includeShared')) {
|
||||
this.collection.data.includeShared = true;
|
||||
}
|
||||
|
||||
this.listenToOnce(this.collection, 'sync', () => {
|
||||
this.createView('list', 'crm:views/record/list-activities-dashlet', {
|
||||
selector: '> .list-container',
|
||||
pagination: false,
|
||||
type: 'list',
|
||||
rowActionsView: this.rowActionsView,
|
||||
checkboxes: false,
|
||||
collection: this.collection,
|
||||
multiListLayout: this.listLayout,
|
||||
}, view => {
|
||||
view.render();
|
||||
});
|
||||
});
|
||||
|
||||
this.collection.fetch();
|
||||
}
|
||||
|
||||
actionRefresh() {
|
||||
this.refreshInternal();
|
||||
}
|
||||
|
||||
autoRefresh() {
|
||||
this.refreshInternal({skipNotify: true});
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {{skipNotify?: boolean}} [options]
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
async refreshInternal(options = {}) {
|
||||
if (!options.skipNotify) {
|
||||
Espo.Ui.notifyWait();
|
||||
}
|
||||
|
||||
await this.collection.fetch({
|
||||
previousTotal: this.collection.total,
|
||||
previousDataList: this.collection.models.map(model => {
|
||||
return Espo.Utils.cloneDeep(model.attributes);
|
||||
}),
|
||||
});
|
||||
|
||||
if (!options.skipNotify) {
|
||||
Espo.Ui.notify();
|
||||
}
|
||||
}
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
actionCreateActivity(data) {
|
||||
const scope = data.scope;
|
||||
const attributes = {};
|
||||
|
||||
this.populateAttributesAssignedUser(scope, attributes);
|
||||
|
||||
const helper = new RecordModalHelper();
|
||||
|
||||
helper.showCreate(this, {
|
||||
entityType: scope,
|
||||
attributes: attributes,
|
||||
afterSave: () => {
|
||||
this.actionRefresh();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
actionCreateMeeting() {
|
||||
const attributes = {};
|
||||
|
||||
this.populateAttributesAssignedUser('Meeting', attributes);
|
||||
|
||||
const helper = new RecordModalHelper();
|
||||
|
||||
helper.showCreate(this, {
|
||||
entityType: 'Meeting',
|
||||
attributes: attributes,
|
||||
afterSave: () => {
|
||||
this.actionRefresh();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
actionCreateCall() {
|
||||
const attributes = {};
|
||||
|
||||
this.populateAttributesAssignedUser('Call', attributes);
|
||||
|
||||
const helper = new RecordModalHelper();
|
||||
|
||||
helper.showCreate(this, {
|
||||
entityType: 'Call',
|
||||
attributes: attributes,
|
||||
afterSave: () => {
|
||||
this.actionRefresh();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
populateAttributesAssignedUser(scope, attributes) {
|
||||
if (this.getMetadata().get(['entityDefs', scope, 'fields', 'assignedUsers'])) {
|
||||
attributes['assignedUsersIds'] = [this.getUser().id];
|
||||
attributes['assignedUsersNames'] = {};
|
||||
attributes['assignedUsersNames'][this.getUser().id] = this.getUser().get('name');
|
||||
} else {
|
||||
attributes['assignedUserId'] = this.getUser().id;
|
||||
attributes['assignedUserName'] = this.getUser().get('name');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default ActivitiesDashletView;
|
||||
195
client/modules/crm/src/views/dashlets/calendar.js
Normal file
195
client/modules/crm/src/views/dashlets/calendar.js
Normal file
@@ -0,0 +1,195 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
import BaseDashletView from 'views/dashlets/abstract/base';
|
||||
|
||||
class CalendarDashletView extends BaseDashletView {
|
||||
|
||||
name = 'Calendar'
|
||||
noPadding = true
|
||||
|
||||
templateContent =`<div class="calendar-container">{{{calendar}}}</div>`
|
||||
|
||||
afterRender() {
|
||||
const mode = this.getOption('mode');
|
||||
|
||||
if (mode === 'timeline') {
|
||||
const userList = [];
|
||||
const userIdList = this.getOption('usersIds') || [];
|
||||
const userNames = this.getOption('usersNames') || {};
|
||||
|
||||
userIdList.forEach(id => {
|
||||
userList.push({
|
||||
id: id,
|
||||
name: userNames[id] || id,
|
||||
});
|
||||
});
|
||||
|
||||
const viewName = this.getMetadata().get(['clientDefs', 'Calendar', 'timelineView']) ||
|
||||
'crm:views/calendar/timeline';
|
||||
|
||||
this.createView('calendar', viewName, {
|
||||
selector: '> .calendar-container',
|
||||
header: false,
|
||||
calendarType: 'shared',
|
||||
userList: userList,
|
||||
enabledScopeList: this.getOption('enabledScopeList'),
|
||||
suppressLoadingAlert: true,
|
||||
}, view => {
|
||||
view.render();
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
let teamIdList = null;
|
||||
|
||||
if (['basicWeek', 'month', 'basicDay'].includes(mode)) {
|
||||
teamIdList = this.getOption('teamsIds');
|
||||
}
|
||||
|
||||
const viewName = this.getMetadata().get(['clientDefs', 'Calendar', 'calendarView']) ||
|
||||
'crm:views/calendar/calendar';
|
||||
|
||||
this.createView('calendar', viewName, {
|
||||
mode: mode,
|
||||
selector: '> .calendar-container',
|
||||
header: false,
|
||||
enabledScopeList: this.getOption('enabledScopeList'),
|
||||
containerSelector: this.getSelector(),
|
||||
teamIdList: teamIdList,
|
||||
scrollToNowSlots: 3,
|
||||
suppressLoadingAlert: true,
|
||||
}, view => {
|
||||
this.listenTo(view, 'view', () => {
|
||||
if (this.getOption('mode') === 'month') {
|
||||
const title = this.getOption('title');
|
||||
|
||||
const $container = $('<span>')
|
||||
.append(
|
||||
$('<span>').text(title),
|
||||
' <span class="chevron-right"></span> ',
|
||||
$('<span>').text(view.getTitle())
|
||||
);
|
||||
|
||||
const $headerSpan = this.$el.closest('.panel').find('.panel-heading > .panel-title > span');
|
||||
|
||||
$headerSpan.html($container.get(0).innerHTML);
|
||||
}
|
||||
});
|
||||
|
||||
view.render();
|
||||
|
||||
this.on('resize', () => {
|
||||
setTimeout(() => view.adjustSize(), 50);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
setupActionList() {
|
||||
this.actionList.unshift({
|
||||
name: 'viewCalendar',
|
||||
text: this.translate('View Calendar', 'labels', 'Calendar'),
|
||||
url: '#Calendar',
|
||||
iconClass: 'far fa-calendar-alt',
|
||||
onClick: () => this.actionViewCalendar(),
|
||||
});
|
||||
}
|
||||
|
||||
setupButtonList() {
|
||||
if (this.getOption('mode') !== 'timeline') {
|
||||
this.buttonList.push({
|
||||
name: 'previous',
|
||||
html: '<span class="fas fa-chevron-left"></span>',
|
||||
onClick: () => this.actionPrevious(),
|
||||
});
|
||||
|
||||
this.buttonList.push({
|
||||
name: 'next',
|
||||
html: '<span class="fas fa-chevron-right"></span>',
|
||||
onClick: () => this.actionNext(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {
|
||||
* import('modules/crm/views/calendar/calendar').default |
|
||||
* import('modules/crm/views/calendar/timeline').default
|
||||
* }
|
||||
*/
|
||||
getCalendarView() {
|
||||
return this.getView('calendar');
|
||||
}
|
||||
|
||||
actionRefresh() {
|
||||
const view = this.getCalendarView();
|
||||
|
||||
if (!view) {
|
||||
return;
|
||||
}
|
||||
|
||||
view.actionRefresh();
|
||||
}
|
||||
|
||||
autoRefresh() {
|
||||
const view = this.getCalendarView();
|
||||
|
||||
if (!view) {
|
||||
return;
|
||||
}
|
||||
|
||||
view.actionRefresh({suppressLoadingAlert: true});
|
||||
}
|
||||
|
||||
actionNext() {
|
||||
const view = this.getCalendarView();
|
||||
|
||||
if (!view) {
|
||||
return;
|
||||
}
|
||||
|
||||
view.actionNext();
|
||||
}
|
||||
|
||||
actionPrevious() {
|
||||
const view = this.getCalendarView();
|
||||
|
||||
if (!view) {
|
||||
return;
|
||||
}
|
||||
|
||||
view.actionPrevious();
|
||||
}
|
||||
|
||||
actionViewCalendar() {
|
||||
this.getRouter().navigate('#Calendar', {trigger: true});
|
||||
}
|
||||
}
|
||||
|
||||
export default CalendarDashletView;
|
||||
39
client/modules/crm/src/views/dashlets/calls.js
Normal file
39
client/modules/crm/src/views/dashlets/calls.js
Normal file
@@ -0,0 +1,39 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
define('crm:views/dashlets/calls', ['views/dashlets/abstract/record-list'], function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
name: 'Calls',
|
||||
scope: 'Call',
|
||||
listView: 'crm:views/call/record/list-expanded',
|
||||
rowActionsView: 'crm:views/call/record/row-actions/dashlet',
|
||||
});
|
||||
});
|
||||
|
||||
38
client/modules/crm/src/views/dashlets/meetings.js
Normal file
38
client/modules/crm/src/views/dashlets/meetings.js
Normal file
@@ -0,0 +1,38 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
define('crm:views/dashlets/meetings', ['views/dashlets/abstract/record-list'], function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
name: 'Meetings',
|
||||
scope: 'Meeting',
|
||||
listView: 'crm:views/meeting/record/list-expanded',
|
||||
rowActionsView: 'crm:views/meeting/record/row-actions/dashlet',
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,140 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
define('crm:views/dashlets/opportunities-by-lead-source', ['crm:views/dashlets/abstract/chart'], function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
name: 'OpportunitiesByLeadSource',
|
||||
|
||||
url: function () {
|
||||
let url = 'Opportunity/action/reportByLeadSource?dateFilter=' + this.getDateFilter();
|
||||
|
||||
if (this.getDateFilter() === 'between') {
|
||||
url += '&dateFrom=' + this.getOption('dateFrom') + '&dateTo=' + this.getOption('dateTo');
|
||||
}
|
||||
|
||||
return url;
|
||||
},
|
||||
|
||||
prepareData: function (response) {
|
||||
var data = [];
|
||||
|
||||
for (var label in response) {
|
||||
var value = response[label];
|
||||
|
||||
data.push({
|
||||
label: this.getLanguage().translateOption(label, 'source', 'Lead'),
|
||||
data: [[0, value]]
|
||||
});
|
||||
}
|
||||
|
||||
return data;
|
||||
},
|
||||
|
||||
isNoData: function () {
|
||||
return !this.chartData.length;
|
||||
},
|
||||
|
||||
setupDefaultOptions: function () {
|
||||
this.defaultOptions['dateFrom'] = this.defaultOptions['dateFrom'] || moment().format('YYYY') + '-01-01';
|
||||
this.defaultOptions['dateTo'] = this.defaultOptions['dateTo'] || moment().format('YYYY') + '-12-31';
|
||||
},
|
||||
|
||||
setup: function () {
|
||||
this.currency = this.getConfig().get('defaultCurrency');
|
||||
this.currencySymbol = this.getMetadata().get(['app', 'currency', 'symbolMap', this.currency]) || '';
|
||||
},
|
||||
|
||||
draw: function () {
|
||||
this.flotr.draw(this.$container.get(0), this.chartData, {
|
||||
colors: this.colorList,
|
||||
shadowSize: false,
|
||||
pie: {
|
||||
show: true,
|
||||
explode: 0,
|
||||
lineWidth: 1 * this.fontSizeFactor,
|
||||
fillOpacity: 1,
|
||||
sizeRatio: 0.8,
|
||||
labelFormatter: (total, value) => {
|
||||
const percentage = Math.round(100 * value / total);
|
||||
|
||||
if (percentage < 5) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return '<span class="small numeric-text" style="font-size: 0.8em;color:'+this.textColor+'">' +
|
||||
percentage.toString() +'%' + '</span>';
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
horizontalLines: false,
|
||||
verticalLines: false,
|
||||
outline: '',
|
||||
tickColor: this.tickColor,
|
||||
},
|
||||
yaxis: {
|
||||
showLabels: false,
|
||||
color: this.textColor,
|
||||
},
|
||||
xaxis: {
|
||||
showLabels: false,
|
||||
color: this.textColor,
|
||||
},
|
||||
mouse: {
|
||||
track: true,
|
||||
relative: true,
|
||||
lineColor: this.hoverColor,
|
||||
trackFormatter: (obj) => {
|
||||
const value = this.currencySymbol +
|
||||
'<span class="numeric-text">' + this.formatNumber(obj.y, true) + '</span>';
|
||||
|
||||
const fraction = obj.fraction || 0;
|
||||
const percentage = '<span class="numeric-text">' +
|
||||
(100 * fraction).toFixed(2).toString() +'</span>';
|
||||
|
||||
const label = this.getHelper().escapeString(obj.series.label || this.translate('None'));
|
||||
|
||||
return label + '<br>' + value + ' / ' + percentage + '%';
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
show: true,
|
||||
noColumns: this.getLegendColumnNumber(),
|
||||
container: this.$el.find('.legend-container'),
|
||||
labelBoxMargin: 0,
|
||||
labelFormatter: this.labelFormatter.bind(this),
|
||||
labelBoxBorderColor: 'transparent',
|
||||
backgroundOpacity: 0,
|
||||
},
|
||||
});
|
||||
|
||||
this.adjustLegend();
|
||||
},
|
||||
});
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user