Merge branch 'master' into stable

This commit is contained in:
Yuri Kuznetsov
2014-08-08 16:58:08 +03:00
102 changed files with 819 additions and 193 deletions
+5
View File
@@ -25,6 +25,7 @@ namespace Espo\Controllers;
use Espo\Core\Utils as Utils;
use \Espo\Core\Exceptions\NotFound;
use \Espo\Core\Exceptions\Error;
use \Espo\Core\Exceptions\Forbidden;
class Layout extends \Espo\Core\Controllers\Base
{
@@ -39,6 +40,10 @@ class Layout extends \Espo\Core\Controllers\Base
public function actionUpdate($params, $data)
{
if (!$this->getUser()->isAdmin()) {
throw new Forbidden();
}
$result = $this->getContainer()->get('layout')->set($data, $params['scope'], $params['name']);
if ($result === false) {
@@ -54,7 +54,13 @@ class Notification extends \Espo\Core\Controllers\Base
public function actionNotReadCount()
{
$userId = $this->getUser()->id;
return $this->getService('Notification')->getNotReadCount($userId);
return $this->getService('Notification')->getNotReadCount($userId);
}
public function actionMarkAllRead($params, $data, $request)
{
$userId = $this->getUser()->id;
return $this->getService('Notification')->markAllRead($userId);
}
}
@@ -176,18 +176,23 @@ class Base
}
$result['whereClause']['assignedUserId'] = $this->user->id;
}
if ($this->acl->checkReadOnlyTeam($this->entityName)) {
if (!$this->user->isAdmin() && $this->acl->checkReadOnlyTeam($this->entityName)) {
if (!array_key_exists('whereClause', $result)) {
$result['whereClause'] = array();
}
$result['distinct'] = true;
if (!array_key_exists('joins', $result)) {
$result['joins'] = array();
}
if (!in_array('teams', $result['joins'])) {
$result['joins'][] = 'teams';
$result['leftJoins'][] = 'teams';
}
$result['whereClause']['Team.id'] = $this->user->get('teamsIds');
$result['whereClause']['OR'] = array(
'Team.id' => $this->user->get('teamsIds'),
'assignedUserId' => $this->user->id
);
//$result['whereClause']['Team.id'] = $this->user->get('teamsIds');
}
}
+20 -1
View File
@@ -26,7 +26,11 @@ use \Espo\Core\Interfaces\Injectable;
abstract class Base implements Injectable
{
protected $dependencies = array();
protected $dependencies = array(
'config',
'entityManager',
'user',
);
protected $injections = array();
@@ -53,5 +57,20 @@ abstract class Base implements Injectable
{
return $this->dependencies;
}
protected function getEntityManager()
{
return $this->getInjection('entityManager');
}
protected function getConfig()
{
return $this->getInjection('config');
}
protected function getUser()
{
return $this->getInjection('user');
}
}
@@ -90,6 +90,9 @@ return array (
"tabList" => array("Account", "Contact", "Lead", "Opportunity", "Calendar", "Meeting", "Call", "Task", "Case", "Email"),
"quickCreateList" => array("Account", "Contact", "Lead", "Opportunity", "Meeting", "Call", "Task", "Case"),
'calendarDefaultEntity' => 'Meeting',
'disableExport' => false,
'assignmentEmailNotifications' => false,
'assignmentEmailNotificationsEntityList' => array('Lead', 'Opportunity', 'Task', 'Case'),
'isInstalled' => false,
);
@@ -0,0 +1,58 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
namespace Espo\Hooks\Common;
use Espo\ORM\Entity;
class AssignmentEmailNotification extends \Espo\Core\Hooks\Base
{
public function afterSave(Entity $entity)
{
if (
$this->getConfig()->get('assignmentEmailNotifications')
&&
in_array($entity->getEntityName(), $this->getConfig()->get('assignmentEmailNotificationsEntityList', array()))
) {
$userId = $entity->get('assignedUserId');
if (!empty($userId) && $userId != $this->getUser()->id && $entity->isFieldChanged('assignedUserId')) {
$job = $this->getEntityManager()->getEntity('Job');
$job->set(array(
'serviceName' => 'EmailNotification',
'method' => 'notifyAboutAssignmentJob',
'data' => json_encode(array(
'userId' => $userId,
'assignerUserId' => $this->getUser()->id,
'entityId' => $entity->id,
'entityType' => $entity->getEntityName()
)),
'executeTime' => date('Y-m-d H:i:s'),
));
$this->getEntityManager()->saveEntity($job);
}
}
}
}
@@ -31,6 +31,8 @@
"Tasks": "My Tasks",
"Cases": "My Cases",
"Calendar": "Calendar",
"Calls": "My Calls",
"Meetings": "My Meetings",
"OpportunitiesByStage": "Opportunities by Stage",
"OpportunitiesByLeadSource": "Opportunities by Lead Source",
"SalesByMonth": "Sales by Month",
@@ -1 +1 @@
{"module":"Crm"}
{"view":"Crm:Dashlets.Calendar"}
@@ -0,0 +1 @@
{"view":"Crm:Dashlets.Calls"}
@@ -1 +1 @@
{"module":"Crm"}
{"view":"Crm:Dashlets.Cases"}
@@ -1 +1 @@
{"module":"Crm"}
{"view":"Crm:Dashlets.Leads"}
@@ -0,0 +1 @@
{"view":"Crm:Dashlets.Meetings"}
@@ -1 +1 @@
{"module":"Crm"}
{"view":"Crm:Dashlets.Opportunities"}
@@ -1 +1 @@
{"module":"Crm"}
{"view":"Crm:Dashlets.OpportunitiesByLeadSource"}
@@ -1 +1 @@
{"module":"Crm"}
{"view":"Crm:Dashlets.OpportunitiesByStage"}
@@ -1 +1 @@
{"module":"Crm"}
{"view":"Crm:Dashlets.SalesByMonth"}
@@ -1 +1 @@
{"module":"Crm"}
{"view":"Crm:Dashlets.SalesPipeline"}
@@ -1 +1 @@
{"module":"Crm"}
{"view":"Crm:Dashlets.Tasks"}
@@ -52,7 +52,8 @@
},
"contacts": {
"type": "linkMultiple",
"disabled": true
"disabled": true,
"view": "Crm:Meeting.Fields.Contacts"
},
"leads": {
"type": "linkMultiple",
@@ -47,7 +47,8 @@
},
"contacts": {
"type": "linkMultiple",
"disabled": true
"disabled": true,
"view": "Crm:Meeting.Fields.Contacts"
},
"leads": {
"type": "linkMultiple",
@@ -25,6 +25,8 @@ namespace Espo\Modules\Crm\Services;
use \Espo\Core\Exceptions\Error;
use \Espo\Core\Exceptions\Forbidden;
use \Espo\ORM\Entity;
class Lead extends \Espo\Services\Record
{
protected function getDuplicateWhereClause(Entity $entity)
+2
View File
@@ -1098,7 +1098,9 @@ abstract class Mapper implements IMapper
if ($operator == '<>') {
$oppose = 'NOT';
}
if (!empty($valArr)) {
$whereParts[] = $leftPart . " {$oppose} IN " . "(" . implode(',', $valArr) . ")";
}
}
}
} else {
@@ -113,7 +113,7 @@
"fieldManager": "Create new fields or customize existing ones.",
"userInterface": "Configure UI.",
"authTokens": "Active auth sessions. IP address and last access date.",
"authentication": "Authentication setttings."
"authentication": "Authentication settings."
},
"options": {
"previewSize": {
@@ -114,7 +114,8 @@
"Administration": "Administration",
"Run Import": "Run Import",
"Duplicate": "Duplicate",
"Notifications": "Notifications"
"Notifications": "Notifications",
"Mark all read": "Mark all read"
},
"messages": {
"notModified": "You have not modified the record",
@@ -130,7 +131,13 @@
"fieldShouldBeBetween": "{field} should be between {min} and {max}",
"fieldShouldBeLess": "{field} should be less then {value}",
"fieldShouldBeGreater": "{field} should be greater then {value}",
"fieldBadPasswordConfirm": "{field} confirmed improperly"
"fieldBadPasswordConfirm": "{field} confirmed improperly",
"assignmentEmailNotificationSubject": "EspoCRM {entityType}: {Entity.name}",
"assignmentEmailNotificationBody": "{assignerUserName} has assigned {entityType} '{Entity.name}' to you\n\n{recordUrl}",
"confirmation": "Are you sure?",
"removeRecordConfirmation": "Are you sure you want to remove the record?",
"unlinkRecordConfirmation": "Are you sure you want to unlink relationship?",
"removeSelectedRecordsConfirmation": "Are you sure you want to remove selected records?"
},
"boolFilters": {
"onlyMy": "Only My",
@@ -19,7 +19,9 @@
"smtpPassword": "Password",
"smtpEmailAddress": "Email Address",
"exportDelimiter": "Export Delimiter"
"exportDelimiter": "Export Delimiter",
"receiveAssignmentEmailNotifications": "Receive Email Notifications upon Assignment"
},
"links": {
},
@@ -28,5 +30,8 @@
"0": "Sunday",
"1": "Monday"
}
},
"labels": {
"Notifications": "Notifications"
}
}
@@ -28,5 +28,8 @@
"read": "Read",
"edit": "Edit",
"delete": "Delete"
},
"messages": {
"changesAfterClearCache": "All changes in an access control will be applied after cache will be cleared."
}
}
@@ -47,7 +47,9 @@
"ldapUserLoginFilter": "User Login Filter",
"ldapAccountDomainNameShort": "Account Domain Name Short",
"ldapOptReferrals": "Opt Referrals",
"disableExport": "Disable Export (only admin is allowed)"
"disableExport": "Disable Export (only admin is allowed)",
"assignmentEmailNotifications": "Send Email Notifications upon Assignment",
"assignmentEmailNotificationsEntityList": "Entities to Notify About"
},
"options": {
"weekStart": {
@@ -59,6 +61,7 @@
"System": "System",
"Locale": "Locale",
"SMTP": "SMTP",
"Configuration": "Configuration"
"Configuration": "Configuration",
"Notifications": "Notifications"
}
}
@@ -28,5 +28,11 @@
"rows": [
[{"name": "exportDelimiter"}]
]
},
{
"label": "Notifications",
"rows": [
[{"name": "receiveAssignmentEmailNotifications"}]
]
}
]
@@ -14,5 +14,11 @@
[{"name": "outboundEmailFromName"}, {"name": "outboundEmailFromAddress"}],
[{"name": "outboundEmailIsShared"}]
]
},
{
"label": "Notifications",
"rows": [
[{"name": "assignmentEmailNotifications"}, {"name": "assignmentEmailNotificationsEntityList"}]
]
}
]
@@ -11,5 +11,8 @@
"teams":{
"create":false
}
}
},
"views": {
"list": "Role.List"
}
}
@@ -83,6 +83,10 @@
"default": ",",
"required": true,
"maxLength": 1
},
"receiveAssignmentEmailNotifications": {
"type": "bool",
"default": true
}
}
}
@@ -187,6 +187,14 @@
"disableExport": {
"type": "bool",
"default": false
},
"assignmentEmailNotifications": {
"type": "bool",
"default": false
},
"assignmentEmailNotificationsEntityList": {
"type": "array",
"translation": "Global.scopeNamesPlural"
}
}
}
@@ -0,0 +1,118 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
namespace Espo\Services;
use \Espo\Core\Exceptions\Forbidden;
use \Espo\Core\Exceptions\NotFound;
use Espo\ORM\Entity;
class EmailNotification extends \Espo\Core\Services\Base
{
protected function init()
{
$this->dependencies[] = 'metadata';
$this->dependencies[] = 'mailSender';
$this->dependencies[] = 'language';
}
protected function getMailSender()
{
return $this->getInjection('mailSender');
}
protected function getMetadata()
{
return $this->getInjection('metadata');
}
protected function getLanguage()
{
return $this->getInjection('language');
}
protected function replaceMessageVariables($text, $entity, $user, $assignerUser)
{
$recordUrl = $this->getConfig()->get('siteUrl') . '#' . $entity->getEntityName() . '/view/' . $entity->id;
$text = str_replace('{userName}', $user->get('name'), $text);
$text = str_replace('{assignerUserName}', $assignerUser->get('name'), $text);
$text = str_replace('{recordUrl}', $recordUrl, $text);
$text = str_replace('{entityType}', $this->getLanguage()->translate($entity->getEntityName(), 'scopeNames'), $text);
$fields = $entity->getFields();
foreach ($fields as $field => $d) {
$text = str_replace('{Entity.' . $field . '}', $entity->get($field), $text);
}
return $text;
}
public function notifyAboutAssignmentJob($data)
{
$userId = $data['userId'];
$assignerUserId = $data['assignerUserId'];
$entityId = $data['entityId'];
$entityType = $data['entityType'];
$user = $this->getEntityManager()->getEntity('User', $userId);
$prefs = $this->getEntityManager()->getEntity('Preferences', $userId);
if (!$prefs) {
return true;
}
if (!$prefs->get('receiveAssignmentEmailNotifications')) {
return true;
}
$assignerUser = $this->getEntityManager()->getEntity('User', $assignerUserId);
$entity = $this->getEntityManager()->getEntity($entityType, $entityId);
if ($user && $entity && $assignerUser && $entity->get('assignedUserId') == $userId) {
$emailAddress = $user->get('emailAddress');
if (!empty($emailAddress)) {
$email = $this->getEntityManager()->getEntity('Email');
$subject = $this->getLanguage()->translate('assignmentEmailNotificationSubject', 'messages', $entity->getEntityName());
$body = $this->getLanguage()->translate('assignmentEmailNotificationBody', 'messages', $entity->getEntityName());
$subject = $this->replaceMessageVariables($subject, $entity, $user, $assignerUser);
$body = $this->replaceMessageVariables($body, $entity, $user, $assignerUser);
$email->set(array(
'subject' => $subject,
'body' => $body,
'isHtml' => false,
'to' => $emailAddress
));
$this->getMailSender()->send($email);
}
}
return true;
}
}
+2 -13
View File
@@ -28,8 +28,7 @@ use \Espo\Core\Exceptions\NotFound;
use Espo\ORM\Entity;
class GlobalSearch extends \Espo\Core\Services\Base
{
{
protected $dependencies = array(
'entityManager',
'user',
@@ -48,11 +47,6 @@ class GlobalSearch extends \Espo\Core\Services\Base
{
return $this->injections['entityManager'];
}
protected function getUser()
{
return $this->injections['user'];
}
protected function getAcl()
{
@@ -62,12 +56,7 @@ class GlobalSearch extends \Espo\Core\Services\Base
protected function getMetadata()
{
return $this->injections['metadata'];
}
protected function getConfig()
{
return $this->injections['config'];
}
}
public function find($query, $offset)
{
-15
View File
@@ -64,21 +64,11 @@ class Import extends \Espo\Core\Services\Base
{
return $this->injections['selectManagerFactory'];
}
protected function getEntityManager()
{
return $this->injections['entityManager'];
}
protected function getFileManager()
{
return $this->injections['fileManager'];
}
protected function getUser()
{
return $this->injections['user'];
}
protected function getAcl()
{
@@ -90,11 +80,6 @@ class Import extends \Espo\Core\Services\Base
return $this->injections['metadata'];
}
protected function getConfig()
{
return $this->injections['config'];
}
protected function getServiceFactory()
{
return $this->injections['serviceFactory'];
@@ -84,6 +84,14 @@ class Notification extends \Espo\Core\Services\Base
))->count();
}
public function markAllRead($userId)
{
$pdo = $this->getEntityManager()->getPDO();
$sql = "UPDATE notification SET `read` = 1 WHERE user_id = ".$pdo->quote($userId)." AND `read` = 0";
$pdo->prepare($sql)->execute();
return true;
}
public function getList($userId, array $params = array())
{
$searchParams = array();
+1 -16
View File
@@ -73,11 +73,6 @@ class Record extends \Espo\Core\Services\Base
{
$this->entityName = $entityName;
}
protected function getEntityManager()
{
return $this->injections['entityManager'];
}
protected function getServiceFactory()
{
@@ -88,11 +83,6 @@ class Record extends \Espo\Core\Services\Base
{
return $this->injections['selectManagerFactory'];
}
protected function getUser()
{
return $this->injections['user'];
}
protected function getAcl()
{
@@ -102,12 +92,7 @@ class Record extends \Espo\Core\Services\Base
protected function getFileManager()
{
return $this->injections['fileManager'];
}
protected function getConfig()
{
return $this->injections['config'];
}
}
protected function getPreferences()
{
+1 -10
View File
@@ -63,20 +63,11 @@ class Stream extends \Espo\Core\Services\Base
protected $dependencies = array(
'entityManager',
'config',
'user',
'metadata',
'acl'
);
protected function getEntityManager()
{
return $this->injections['entityManager'];
}
protected function getUser()
{
return $this->injections['user'];
}
protected function getAcl()
{
+5 -2
View File
@@ -70,10 +70,13 @@ execute('git diff --name-only ' + versionFrom, function (stdout) {
var d = new Date();
var dateN = ((d.getMonth() + 1).toString());
var monthN = ((d.getMonth() + 1).toString());
monthN = monthN.length == 1 ? '0' + monthN : monthN;
var dateN = d.getDate().toString();
dateN = dateN.length == 1 ? '0' + dateN : dateN;
var date = d.getFullYear().toString() + '-' + dateN + '-' + (d.getDate()).toString();
var date = d.getFullYear().toString() + '-' + monthN + '-' + dateN.toString();
execute('git tag', function (stdout) {
var versionList = [];
@@ -17,7 +17,7 @@
<div class="col-sm-4">
<div class="btn-group pull-right">
{{#each ../modeList}}
<button class="btn btn-default{{#ifEqual this ../../mode}} active{{/ifEqual}}" data-action="mode" data-mode="{{this}}">{{translate this scope='Calendar' category='modes'}}</button>
<button class="btn btn-default{{#ifEqual this ../../mode}} active{{/ifEqual}}" data-action="mode" data-mode="{{./this}}">{{translate this scope='Calendar' category='modes'}}</button>
{{/each}}
</div>
</div>
@@ -2,7 +2,7 @@
<div class="scope-switcher">
{{#each scopeList}}
<label>
<input type="radio" name="scope"{{#ifEqual this ../scope}} checked{{/ifEqual}} value="{{this}}">
<input type="radio" name="scope"{{#ifEqual this ../scope}} checked{{/ifEqual}} value="{{./this}}">
{{translate this category='scopeNames'}}
</label>&nbsp;
{{/each}}
@@ -1,5 +1,5 @@
<select name="{{name}}" class="form-control main-element">
{{#each list}}
<option value="{{this}}">{{this}}</optopn>
<option value="{{./this}}">{{./this}}</optopn>
{{/each}}
</select>
@@ -4,8 +4,8 @@
<ul class="list-group">
{{#each folders}}
<li class="list-group-item clearfix">
{{this}}
<button class="btn btn-default pull-right" data-value="{{this}}" data-action="select">{{translate 'Select'}}</button>
{{./this}}
<button class="btn btn-default pull-right" data-value="{{./this}}" data-action="select">{{translate 'Select'}}</button>
</li>
{{/each}}
</ul>
@@ -8,7 +8,7 @@
{{#each scopes}}
<div>
<label><h4><input type="checkbox" class="check-scope" data-scope="{{this}}"> {{translate this category='scopeNames'}}</h4></label>
<label><h4><input type="checkbox" class="check-scope" data-scope="{{./this}}"> {{translate this category='scopeNames'}}</h4></label>
<div class="edit-container-{{toDom this}} hide">
{{{var this ../this}}}
</div>
@@ -1,7 +1,7 @@
<div class="btn-group button-container">
<button class="btn btn-default all{{#ifEqual currentTab 'all'}} active{{/ifEqual}} scope-switcher" data-scope="">{{translate 'All'}}</button>
{{#each scopeList}}
<button class="btn btn-default all{{#ifEqual ../currentTab this}} active{{/ifEqual}} scope-switcher" data-scope="{{this}}">{{translate this category='scopeNamesPlural'}}</button>
<button class="btn btn-default all{{#ifEqual ../currentTab this}} active{{/ifEqual}} scope-switcher" data-scope="{{./this}}">{{translate this category='scopeNamesPlural'}}</button>
{{/each}}
</div>
@@ -1,6 +1,6 @@
<div class="btn-group button-container">
{{#each tabList}}
<button class="btn btn-default all{{#ifEqual ../currentTab this}} active{{/ifEqual}} tab-switcher" data-tab="{{this}}">{{translate this}}</button>
<button class="btn btn-default all{{#ifEqual ../currentTab this}} active{{/ifEqual}} tab-switcher" data-tab="{{./this}}">{{translate this}}</button>
{{/each}}
</div>
@@ -79,7 +79,7 @@ Espo.define('Crm:Views.Calendar.Modals.Edit', 'Views.Modals.Edit', function (Dep
onClick: function (dialog) {
var model = this.getView('edit').model;
if (confirm(this.translate('Are you sure?'))) {
if (confirm(this.translate('removeRecordConfirmation', 'messages'))) {
var $buttons = dialog.$el.find('.modal-footer button');
$buttons.addClass('disabled');
model.destroy({
@@ -48,7 +48,7 @@
},
actionSendInvitations: function () {
if (confirm(this.translate('Are you sure?'))) {
if (confirm(this.translate('confirmation', 'messages'))) {
this.$el.find('button[data-action="sendInvitations"]').addClass('disabled');
this.notify('Sending...');
$.ajax({
@@ -0,0 +1,83 @@
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
Espo.define('Crm:Views.Dashlets.Calls', 'Views.Dashlets.Abstract.RecordList', function (Dep) {
return Dep.extend({
name: 'Calls',
scope: 'Call',
defaultOptions: {
sortBy: 'createdAt',
asc: false,
displayRecords: 5,
columnLayout: [
{
name: 'name',
link: true,
sortable: false,
width: 40,
},
{
name: 'status',
sortable: false,
},
{
name: 'dateStart',
sortable: false,
}
],
expandedLayout: {
rows: [
[
{
name: 'name',
link: true,
}
],
[
{
name: 'status'
},
{
name: 'dateStart'
}
]
]
},
searchData: {
bool: {
onlyMy: true,
},
advanced: {
status: {
type: 'notIn',
value: ['Held', 'Not Held']
}
}
},
},
});
});
@@ -29,6 +29,8 @@ Espo.define('Crm:Views.Dashlets.Cases', 'Views.Dashlets.Abstract.RecordList', fu
scope: 'Case',
defaultOptions: {
sortBy: 'number',
asc: false,
displayRecords: 5,
columnLayout: [
{
@@ -28,6 +28,8 @@ Espo.define('Crm:Views.Dashlets.Leads', 'Views.Dashlets.Abstract.RecordList', fu
scope: 'Lead',
defaultOptions: {
sortBy: 'createdAt',
asc: false,
displayRecords: 5,
columnLayout: [
{
@@ -0,0 +1,83 @@
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
Espo.define('Crm:Views.Dashlets.Meetings', 'Views.Dashlets.Abstract.RecordList', function (Dep) {
return Dep.extend({
name: 'Meetings',
scope: 'Meeting',
defaultOptions: {
sortBy: 'createdAt',
asc: false,
displayRecords: 5,
columnLayout: [
{
name: 'name',
link: true,
sortable: false,
width: 40,
},
{
name: 'status',
sortable: false,
},
{
name: 'dateStart',
sortable: false,
}
],
expandedLayout: {
rows: [
[
{
name: 'name',
link: true,
}
],
[
{
name: 'status'
},
{
name: 'dateStart'
}
]
]
},
searchData: {
bool: {
onlyMy: true,
},
advanced: {
status: {
type: 'notIn',
value: ['Held', 'Not Held']
}
}
},
},
});
});
@@ -28,6 +28,8 @@ Espo.define('Crm:Views.Dashlets.Opportunities', 'Views.Dashlets.Abstract.RecordL
scope: 'Opportunity',
defaultOptions: {
sortBy: 'createdAt',
asc: false,
displayRecords: 5,
columnLayout: [
{
@@ -28,6 +28,8 @@ Espo.define('Crm:Views.Dashlets.Tasks', 'Views.Dashlets.Abstract.RecordList', fu
scope: 'Task',
defaultOptions: {
sortBy: 'createdAt',
asc: false,
displayRecords: 5,
columnLayout: [
{
@@ -123,7 +123,8 @@ Espo.define('Crm:Views.Lead.Convert', 'View', function (Dep) {
var scopes = [];
this.scopes.forEach(function (scope) {
if (this.$el.find('input[data-scope="' + scope + '"]').get(0).checked) {
var el = this.$el.find('input[data-scope="' + scope + '"]').get(0);
if (el && el.checked) {
scopes.push(scope);
}
}.bind(this));
@@ -48,7 +48,7 @@ Espo.define('Crm:Views.Meeting.Detail', 'Views.Detail', function (Dep) {
},
actionSendInvitations: function () {
if (confirm(this.translate('Are you sure?'))) {
if (confirm(this.translate('confirmation', 'messages'))) {
this.$el.find('button[data-action="sendInvitations"]').addClass('disabled');
this.notify('Sending...');
$.ajax({
@@ -0,0 +1,40 @@
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
Espo.define('Crm:Views.Meeting.Fields.Contacts', 'Views.Fields.LinkMultiple', function (Dep) {
return Dep.extend({
getSelectFilters: function () {
if (this.model.get('parentType') == 'Account' && this.model.get('parentId')) {
return {
'account': {
type: 'equals',
field: 'accountId',
value: this.model.get('parentId'),
valueName: this.model.get('parentName'),
}
};
}
},
});
});
@@ -27,7 +27,7 @@ Espo.define('Crm:Views.Target.Detail', 'Views.Detail', function (Dep) {
var id = this.model.id;
var self = this;
if (confirm(this.translate('Are you sure?'))) {
if (confirm(this.translate('confirmation', 'messages'))) {
self.notify('Please wait...');
$.ajax({
url: 'Target/action/convert',
@@ -4,7 +4,7 @@
<div id="scopes-menu" class="col-sm-3">
<ul class="list-group">
{{#each scopeList}}
<li class="list-group-item"><a href="javascript:" class="scope-link" data-scope="{{this}}">{{translate this category='scopeNamesPlural'}}</a></li>
<li class="list-group-item"><a href="javascript:" class="scope-link" data-scope="{{./this}}">{{translate this category='scopeNamesPlural'}}</a></li>
{{/each}}
</ul>
</div>
@@ -3,7 +3,7 @@
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">{{translate 'Add Field' scope='Admin'}} <span class="caret"></span></button>
<ul class="dropdown-menu">
{{#each typeList}}
<li><a href="javascript:" data-action="addField" data-scope="{{../scope}}" data-type="{{this}}">{{translate this category='fieldTypes' scope='Admin'}}</a></li>
<li><a href="javascript:" data-action="addField" data-scope="{{../scope}}" data-type="{{./this}}">{{translate this category='fieldTypes' scope='Admin'}}</a></li>
{{/each}}
</ul>
</div>
@@ -147,7 +147,7 @@
<header>{{translate 'Available Fields' scope='Admin'}}</header>
<ul class="disabled cells clearfix">
{{#each disabledFields}}
<li class="cell" data-name="{{this}}">{{translate this scope=../scope category='fields'}}
<li class="cell" data-name="{{./this}}">{{translate this scope=../scope category='fields'}}
&nbsp;<a href="javascript:" data-action="remove-field" class="remove-field"><i class="glyphicon glyphicon-remove"></i></a>
</li>
{{/each}}
@@ -13,7 +13,7 @@
<ul class="list-unstyled">
{{#each ../typeList}}
<li>
<button style="display: block;" class="layout-link btn btn-link" data-type="{{this}}" data-scope="{{../this}}">{{translate this scope='Admin' category='layouts'}}</button>
<button style="display: block;" class="layout-link btn btn-link" data-type="{{./this}}" data-scope="{{.././this}}">{{translate this scope='Admin' category='layouts'}}</button>
</li>
{{/each}}
</ul>
@@ -70,7 +70,7 @@
<header>{{translate 'Enabled' scope='Admin'}}</header>
<ul class="enabled connected">
{{#each layout}}
<li draggable="true" {{#each ../dataAttributes}}data-{{this}}="{{prop ../this this}}" {{/each}}>
<li draggable="true" {{#each ../dataAttributes}}data-{{./this}}="{{prop ../this this}}" {{/each}}>
<div class="left">
<label>{{label}}</label>
</div>
@@ -107,10 +107,10 @@
<div class="form-group">
<label>{{translate this}}</label>
{{#ifPropEquals ../../dataAttributesDefs this 'text'}}
<input type="text" name="{{../this}}" value="" size="8" maxlength="8" class="form-control input-small">
<input type="text" name="{{.././this}}" value="" size="8" maxlength="8" class="form-control input-small">
{{/ifPropEquals}}
{{#ifPropEquals ../../dataAttributesDefs this 'bool'}}
<select name="{{../this}}" class="form-control input-small">
<select name="{{.././this}}" class="form-control input-small">
<option value="">no</option>
<option value="true">yes</option>
</select>
@@ -1,12 +1,12 @@
<div class="link-container list-group">
{{#each selected}}
<div class="list-group-item" data-value="{{this}}">
<div class="list-group-item" data-value="{{./this}}">
{{#if ../translatedOptions}}
{{prop ../../translatedOptions this}}&nbsp;
{{else}}
{{this}}&nbsp;
{{./this}}&nbsp;
{{/if}}
<a href="javascript:" class="pull-right" data-value="{{this}}" data-action="removeValue"><span class="glyphicon glyphicon-remove"></a>
<a href="javascript:" class="pull-right" data-value="{{./this}}" data-action="removeValue"><span class="glyphicon glyphicon-remove"></a>
</div>
{{/each}}
</div>
+2 -2
View File
@@ -8,7 +8,7 @@
{{#if link}}
<a href="{{link}}" class="btn btn-{{#if style}}{{style}}{{else}}default{{/if}}">{{translate label scope=../../scope}}</a>
{{else}}
<button type="button" class="btn btn-{{#if style}}{{style}}{{else}}default{{/if}} action"{{#if action}} data-action={{action}}{{/if}}{{#each data}} data-{{@key}}="{{this}}"{{/each}}>
<button type="button" class="btn btn-{{#if style}}{{style}}{{else}}default{{/if}} action"{{#if action}} data-action={{action}}{{/if}}{{#each data}} data-{{@key}}="{{./this}}"{{/each}}>
{{#if icon}}<span class="{{icon}}"></span>{{/if}}
{{translate label scope=../../scope}}
</button>
@@ -21,7 +21,7 @@
</button>
<ul class="dropdown-menu">
{{#each items.dropdown}}
<li><a {{#if link}}href="{{link}}"{{else}}href="javascript:"{{/if}} class="action" {{#if action}} data-action={{action}}{{/if}}{{#each data}} data-{{@key}}="{{this}}"{{/each}}>{{translate label scope=../../scope}}</a></li>
<li><a {{#if link}}href="{{link}}"{{else}}href="javascript:"{{/if}} class="action" {{#if action}} data-action={{action}}{{/if}}{{#each data}} data-{{@key}}="{{./this}}"{{/each}}>{{translate label scope=../../scope}}</a></li>
{{/each}}
</ul>
{{/if}}
@@ -8,7 +8,7 @@
<label class="control-label">{{translate 'Entity Type' scope='Import'}}</label>
<select id="import-entity-type" class="form-control">
{{#each entityList}}
<option value="{{this}}" {{#ifEqual this ../entityType}}selected{{/ifEqual}}>{{translate this category='scopeNamesPlural'}}</option>
<option value="{{./this}}" {{#ifEqual this ../entityType}}selected{{/ifEqual}}>{{translate this category='scopeNamesPlural'}}</option>
{{/each}}
</select>
</div>
@@ -103,7 +103,7 @@
<label class="control-label">{{translate 'Currency' scope='Import'}}</label>
<select class="form-control" id="import-currency">
{{#each currencyList}}
<option value="{{this}}">{{this}}</option>
<option value="{{./this}}">{{./this}}</option>
{{/each}}
</select>
</div>
@@ -19,7 +19,7 @@
</button>
<ul class="dropdown-menu pull-left">
{{#each fieldList}}
<li><a href="javascript:" data-action="addField" data-name="{{this}}">{{translate this scope=../scope category='fields'}}</a></li>
<li><a href="javascript:" data-action="addField" data-name="{{./this}}">{{translate this scope=../scope category='fields'}}</a></li>
{{/each}}
</ul>
</div>
@@ -2,7 +2,7 @@
{{#each dashletList}}
<li class="list-group-item clearfix">
{{translate this category="dashlets"}}
<button class="btn btn-default pull-right add" data-name="{{this}}">{{translate 'Add'}}</button>
<button class="btn btn-default pull-right add" data-name="{{./this}}">{{translate 'Add'}}</button>
</li>
{{/each}}
</ul>
@@ -4,8 +4,8 @@
<ul class="list-group">
{{#each optionList}}
<li class="list-group-item clearfix">
{{#if ../translatedOptions}}{{prop ../../translatedOptions this}}{{else}}{{this}}{{/if}}
<button class="btn btn-default pull-right" data-value="{{this}}" data-action="add">{{translate 'Add'}}</button>
{{#if ../translatedOptions}}{{prop ../../translatedOptions this}}{{else}}{{./this}}{{/if}}
<button class="btn btn-default pull-right" data-value="{{./this}}" data-action="add">{{translate 'Add'}}</button>
</li>
{{/each}}
</ul>
@@ -5,7 +5,7 @@
{{#each duplicates}}
<tr>
<td>
<a href="#{{../scope}}/view/{{@key}}">{{this}}</a>
<a href="#{{../scope}}/view/{{@key}}">{{./this}}</a>
</td>
</tr>
{{/each}}
@@ -6,7 +6,7 @@
<button class="btn btn-default dropdown-toggle" data-toggle="dropdown" tabindex="-1">{{translate 'Select Field'}} <span class="caret"></span></button>
<ul class="dropdown-menu pull-left filter-list">
{{#each ../fields}}
<li><a href="javascript:" data-name="{{this}}" data-action="add-field">{{translate this scope=../../scope category='fields'}}</a></li>
<li><a href="javascript:" data-name="{{./this}}" data-action="add-field">{{translate this scope=../../scope category='fields'}}</a></li>
{{/each}}
</ul>
</div>
@@ -1,5 +1,5 @@
<div class="panel panel-default">
<div class="panel-heading">{{translate 'Notifications'}}</div>
<div class="panel-heading"><a class="pull-right" href="javascript:" data-action="markAllNotificationsRead">{{translate 'Mark all read'}}</a>{{translate 'Notifications'}}</div>
<div class="panel-body">
<div class="list-container">
{{translate 'Loading...'}}
@@ -13,7 +13,7 @@
</button>
<ul class="dropdown-menu">
{{#each actions}}
<li><a {{#if link}}href="{{link}}"{{else}}href="javascript:"{{/if}} class="action" data-panel="{{../../name}}" {{#if action}} data-action={{action}}{{/if}}{{#each data}} data-{{@key}}="{{this}}"{{/each}}>{{translate label scope=../scope}}</a></li>
<li><a {{#if link}}href="{{link}}"{{else}}href="javascript:"{{/if}} class="action" data-panel="{{../../name}}" {{#if action}} data-action={{action}}{{/if}}{{#each data}} data-{{@key}}="{{./this}}"{{/each}}>{{translate label scope=../scope}}</a></li>
{{/each}}
</ul>
{{/if}}
@@ -1,8 +1,8 @@
<div class="row">
{{#each fields}}
<div class="cell cell-{{this}} form-group col-sm-6 col-md-12">
<label class="control-label label-{{this}}">{{translate this scope=../model.name category='fields'}}</label>
<div class="field field-{{this}}">
<div class="cell cell-{{./this}} form-group col-sm-6 col-md-12">
<label class="control-label label-{{./this}}">{{translate this scope=../model.name category='fields'}}</label>
<div class="field field-{{./this}}">
{{{var this ../this}}}
</div>
</div>
@@ -1,8 +1,8 @@
<div class="row">
{{#each fields}}
<div class="cell cell-{{this}} form-group col-sm-6 col-md-12">
<label class="control-label label-{{this}}">{{translate this scope=../model.name category='fields'}}</label>
<div class="field field-{{this}}">
<div class="cell cell-{{./this}} form-group col-sm-6 col-md-12">
<label class="control-label label-{{./this}}">{{translate this scope=../model.name category='fields'}}</label>
<div class="field field-{{./this}}">
{{{var this ../this}}}
</div>
</div>
@@ -17,7 +17,7 @@
{{/if}}
{{#each boolFilters}}
<li class="checkbox"><label><input type="checkbox" data-role="boolFilterCheckbox" name="{{this}}" {{#ifPropEquals ../bool this true}}checked{{/ifPropEquals}}> {{translate this scope=../scope category='boolFilters'}}</label></li>
<li class="checkbox"><label><input type="checkbox" data-role="boolFilterCheckbox" name="{{./this}}" {{#ifPropEquals ../bool this true}}checked{{/ifPropEquals}}> {{translate this scope=../scope category='boolFilters'}}</label></li>
{{/each}}
</ul>
</div>
@@ -50,7 +50,7 @@
<div class="advanced-filters-bar" style="margin-bottom: 12px;"></div>
<div class="row advanced-filters hidden">
{{#each filterList}}
<div class="filter {{this}} col-sm-4 col-md-3">
<div class="filter {{./this}} col-sm-4 col-md-3">
{{{var this ../this}}}
</div>
{{/each}}
@@ -9,7 +9,7 @@
</button>
<ul class="dropdown-menu">
{{#each actions}}
<li><a {{#if link}}href="{{link}}"{{else}}href="javascript:"{{/if}} class="action" {{#if action}} data-panel="{{../../name}}" data-action="{{action}}"{{/if}}{{#each data}} data-{{@key}}="{{this}}"{{/each}}>{{translate label scope=../scope}}</a></li>
<li><a {{#if link}}href="{{link}}"{{else}}href="javascript:"{{/if}} class="action" {{#if action}} data-panel="{{../../name}}" data-action="{{action}}"{{/if}}{{#each data}} data-{{@key}}="{{./this}}"{{/each}}>{{translate label scope=../scope}}</a></li>
{{/each}}
</ul>
{{/if}}
@@ -0,0 +1 @@
<span class="text-danger">{{translate 'changesAfterClearCache' scope='Role' category='messages'}}</span>
@@ -33,7 +33,7 @@
<ul class="dropdown-menu" role="menu" aria-labelledby="nav-quick-create-dropdown">
<li class="dropdown-header">{{translate 'Create'}}</li>
{{#each quickCreateList}}
<li><a href="#{{this}}/create" data-name="{{this}}" data-action="quick-create">{{translate this category='scopeNames'}}</a></li>
<li><a href="#{{./this}}/create" data-name="{{./this}}" data-action="quick-create">{{translate this category='scopeNames'}}</a></li>
{{/each}}
</ul>
</li>
+15 -8
View File
@@ -116,27 +116,34 @@ _.extend(Espo.Controller.prototype, {
},
checkAccess: function (action) {
if (this.getUser().isAdmin()) {
return true;
return true;
},
handleAccessGlobal: function () {
if (!this.checkAccessGlobal()) {
throw new Espo.Exceptions.AccessDenied("Denied access to action '" + this.name + "#" + action + "'");
}
if (this.getAcl().check(this.name, action)) {
return true;
}
return false;
},
checkAccessGlobal: function () {
return true;
},
handleCheckAccess: function (action) {
if (!this.checkAccess(action)) {
throw new Espo.Exceptions.AccessDenied("Acl has denied access to action '" + this.name + "#" + action + "'");
throw new Espo.Exceptions.AccessDenied("Denied access to action '" + this.name + "#" + action + "'");
}
},
doAction: function (action, options) {
this.handleAccessGlobal();
action = action || this.defaultAction;
var method = action;
if (!(method in this)) {
throw new Espo.Exceptions.NotFound("Action '" + this.name + "#" + action + "' is not found");
}
}
var preMethod = 'before' + Espo.Utils.upperCaseFirst(method);
var postMethod = 'after' + Espo.Utils.upperCaseFirst(method);
+5 -5
View File
@@ -20,14 +20,14 @@
************************************************************************/
Espo.define('Controllers.Admin', 'Controller', function (Dep) {
return Dep.extend({
return Dep.extend({
checkAccess: function () {
checkAccessGlobal: function () {
if (this.getUser().isAdmin()) {
return true;
}
return false;
},
},
index: function () {
this.main('Admin.Index', null);
@@ -36,7 +36,7 @@ Espo.define('Controllers.Admin', 'Controller', function (Dep) {
layouts: function (options) {
var scope = options.scope || null;
var type = options.type || null;
this.main('Admin.Layouts.Index', {scope: scope, type: type});
},
@@ -49,7 +49,7 @@ Espo.define('Controllers.Admin', 'Controller', function (Dep) {
upgrade: function (options) {
this.main('Admin.Upgrade.Index');
},
},
getSettingsModel: function () {
var model = this.getConfig().clone();
@@ -33,12 +33,7 @@ Espo.define('Controllers.Preferences', 'Controllers.Record', function (Dep) {
},
checkAccess: function (action) {
if (this.getUser().isAdmin()) {
return true;
}
if (action != 'own') {
return false;
}
return true;
},
own: function () {
+10
View File
@@ -25,6 +25,16 @@ Espo.define('Controllers.Record', 'Controller', function (Dep) {
viewMap: null,
defaultAction: 'list',
checkAccess: function (action) {
if (this.getUser().isAdmin()) {
return true;
}
if (this.getAcl().check(this.name, action)) {
return true;
}
return false;
},
initialize: function () {
this.viewMap = this.viewMap || {};
@@ -37,7 +37,7 @@ Espo.define('Views.Admin.FieldManager.List', 'View', function (Dep) {
'click [data-action="removeField"]': function (e) {
var field = $(e.currentTarget).data('name');
if (confirm(this.translate('Are you sure?'))) {
if (confirm(this.translate('confirmation', 'messages'))) {
this.notify('Removing...');
$.ajax({
url: 'Admin/fieldManager/' + this.scope + '/' + field,
@@ -25,25 +25,51 @@ Espo.define('Views.Admin.OutboundEmail', 'Views.Settings.Record.Edit', function
layoutName: 'outboundEmail',
afterRender: function () {
Dep.prototype.afterRender.call(this);
if (!this.model.get('smtpAuth')) {
this.hideField('smtpUsername');
this.hideField('smtpPassword');
dependencyDefs: {
'assignmentEmailNotifications': {
map: {
true: [
{
action: 'show',
fields: ['assignmentEmailNotificationsEntityList']
}
]
},
default: [
{
action: 'hide',
fields: ['assignmentEmailNotificationsEntityList']
}
]
},
'smtpAuth': {
map: {
true: [
{
action: 'show',
fields: ['smtpUsername', 'smtpPassword']
}
]
},
default: [
{
action: 'hide',
fields: ['smtpUsername', 'smtpPassword']
}
]
}
var smtpAuthField = this.getFieldView('smtpAuth');
this.listenTo(smtpAuthField, 'change', function () {
var smtpAuth = smtpAuthField.fetch()['smtpAuth'];
if (smtpAuth) {
this.showField('smtpUsername');
this.showField('smtpPassword');
} else {
this.hideField('smtpUsername');
this.hideField('smtpPassword');
}
}.bind(this));
},
setup: function () {
Dep.prototype.setup.call(this);
this.model.defs.fields.assignmentEmailNotificationsEntityList.options = Object.keys(this.getMetadata().get('scopes')).filter(function (scope) {
return this.getMetadata().get('scopes.' + scope + '.tab') && this.getMetadata().get('scopes.' + scope + '.entity');
}, this);
},
afterRender: function () {
Dep.prototype.afterRender.call(this);
var smtpSecurityField = this.getFieldView('smtpSecurity');
this.listenTo(smtpSecurityField, 'change', function () {
+3 -3
View File
@@ -55,9 +55,9 @@ Espo.define('Views.Dashlet', 'View', function (Dep) {
};
var bodySelector = '#dashlet-' + this.id + ' .dashlet-body';
var module = this.getMetadata().get('dashlets.' + this.name + '.module');
this.createView('body', Espo.Utils.composeClassName(module, this.name, 'Dashlets'), {el: bodySelector, id: this.id});
var view = this.getMetadata().get('dashlets.' + this.name + '.view') || 'Dashlets.' + this.name;
this.createView('body', view, {el: bodySelector, id: this.id});
},
refresh: function () {
@@ -74,7 +74,7 @@ Espo.define('Views.Fields.LinkParent', 'Views.Fields.Base', function (Dep) {
if (this.mode != 'list') {
this.addActionHandler('selectLink', function () {
Espo.Ui.notify('Loading...');
this.notify('Loading...');
this.createView('dialog', 'Modals.SelectRecords', {
scope: this.foreignScope,
createButton: this.mode != 'search'
@@ -84,12 +84,14 @@ Espo.define('Views.Fields.LinkParent', 'Views.Fields.Base', function (Dep) {
dialog.once('select', function (model) {
self.$elementName.val(model.get('name'));
self.$elementId.val(model.get('id'));
self.trigger('change');
});
});
});
this.addActionHandler('clearLink', function () {
this.$elementName.val('');
this.$elementId.val('');
this.$elementId.val('');
this.trigger('change');
});
this.events['change select[name="' + this.typeName + '"]'] = function (e) {
+2 -2
View File
@@ -81,7 +81,7 @@ Espo.define('Views.Import.Step1', 'View', function (Dep) {
afterRender: function () {
this.setupFormData();
if (this.getParentView().fileContents) {
if (this.getParentView() && this.getParentView().fileContents) {
this.setFileIsLoaded();
this.preview();
}
@@ -148,7 +148,7 @@ Espo.define('Views.Import.Step1', 'View', function (Dep) {
},
setFileIsLoaded: function () {
$('button[data-action="next"]').removeClass('hidden');
this.$el.find('button[data-action="next"]').removeClass('hidden');
},
preview: function () {
@@ -49,14 +49,22 @@ Espo.define('Views.Notifications.Badge', 'View', function (Dep) {
this.checkUpdates();
},
showNotRead: function (count) {
this.$icon.addClass('warning');
this.$badge.attr('title', this.translate('New notifications') + ': ' + count);
},
hideNotRead: function () {
this.$icon.removeClass('warning');
this.$badge.attr('title', '');
},
checkUpdates: function () {
$.ajax('Notification/action/notReadCount').done(function (count) {
if (count) {
this.$icon.addClass('warning');
this.$badge.attr('title', this.translate('New notifications') + ': ' + count);
this.showNotRead(count);
} else {
this.$icon.removeClass('warning');
this.$badge.attr('title', '');
this.hideNotRead();
}
}.bind(this));
@@ -82,6 +90,10 @@ Espo.define('Views.Notifications.Badge', 'View', function (Dep) {
el: '#notifications-panel',
}, function (view) {
view.render();
this.listenTo(view, 'all-read', function () {
this.hideNotRead();
this.$el.find('.badge-circle-warning').remove();
}, this);
}.bind(this));
$document = $(document);
@@ -25,6 +25,17 @@ Espo.define('Views.Notifications.Panel', 'View', function (Dep) {
template: 'notifications.panel',
events: {
'click [data-action="markAllNotificationsRead"]': function () {
$.ajax({
url: 'Notification/action/markAllRead',
type: 'POST'
}).done(function (count) {
this.trigger('all-read');
}.bind(this));
},
},
setup: function () {
this.wait(true);
this.getCollectionFactory().create('Notification', function (collection) {
@@ -65,10 +65,15 @@ Espo.define('Views.Preferences.Record.Edit', 'Views.Record.Edit', function (Dep)
this.getPreferences().trigger('update');
}, this);
}
},
afterRender: function () {
Dep.prototype.afterRender.call(this);
Dep.prototype.afterRender.call(this);
if (!this.getConfig().get('assignmentEmailNotifications')) {
this.hideField('receiveAssignmentEmailNotifications');
}
var smtpSecurityField = this.getFieldView('smtpSecurity');
this.listenTo(smtpSecurityField, 'change', function () {
+15 -9
View File
@@ -229,7 +229,7 @@ Espo.define('Views.Record.Detail', 'View', function (Dep) {
},
delete: function () {
if (confirm(this.getLanguage().translate("Are you sure you?"))) {
if (confirm(this.translate('removeRecordConfirmation', 'messages'))) {
this.trigger('before:delete');
this.trigger('delete');
@@ -547,6 +547,10 @@ Espo.define('Views.Record.Detail', 'View', function (Dep) {
for (var j in simplifiedLayout[p].rows[i]) {
var cellDefs = simplifiedLayout[p].rows[i][j];
if (!cellDefs.name) {
continue;
}
if (cellDefs == false) {
row.push(false);
@@ -606,7 +610,17 @@ Espo.define('Views.Record.Detail', 'View', function (Dep) {
build: function (callback) {
this.waitForView('record');
var self = this;
if (this.sideView) {
this.createView('side', this.sideView, {
model: this.model,
el: '#' + this.id + ' .side',
readOnly: this.readOnly
});
}
this.getGridLayout(function (layout) {
this.createView('record', 'Base', {
model: this.model,
@@ -620,14 +634,6 @@ Espo.define('Views.Record.Detail', 'View', function (Dep) {
}.bind(this));
if (this.sideView) {
this.createView('side', this.sideView, {
model: this.model,
el: '#' + this.id + ' .side',
readOnly: this.readOnly
});
}
if (this.bottomView) {
this.once('after:render', function () {
this.createView('bottom', this.bottomView, {
+6 -3
View File
@@ -155,7 +155,7 @@ Espo.define('Views.Record.List', 'View', function (Dep) {
var self = this;
if (confirm(this.translate('Are you sure?'))) {
if (confirm(this.translate('removeSelectedRecordsConfirmation', 'messages'))) {
// TODO mass delete
this.notify('Removing...');
for (var i in this.checkedList) {
@@ -433,7 +433,10 @@ Espo.define('Views.Record.List', 'View', function (Dep) {
for (var i in listLayout) {
var col = listLayout[i];
var type = col.type || model.getFieldType(col.name) || 'base';
var type = col.type || model.getFieldType(col.name) || 'base';
if (!col.name) {
continue;
}
var item = {
name: col.name,
view: col.view || model.getFieldParam(col.name, 'view') || this.getFieldManager().getViewName(type),
@@ -711,7 +714,7 @@ Espo.define('Views.Record.List', 'View', function (Dep) {
return false;
}
var self = this;
if (confirm(this.translate('Are you sure?'))) {
if (confirm(this.translate('removeRecordConfirmation', 'messages'))) {
this.collection.remove(model);
this.notify('Removing...');
model.destroy({
@@ -148,7 +148,7 @@ Espo.define('Views.Record.Panels.Relationship', 'Views.Record.Panels.Bottom', fu
actionUnlinkRelated: function (id) {
var self = this;
if (confirm(this.translate('Are you sure?'))) {
if (confirm(this.translate('unlinkRecordConfirmation', 'messages'))) {
var model = this.collection.get(id);
self.notify('Unlinking...');
$.ajax({
@@ -171,7 +171,7 @@ Espo.define('Views.Record.Panels.Relationship', 'Views.Record.Panels.Bottom', fu
actionRemoveRelated: function (id) {
var self = this;
if (confirm(this.translate('Are you sure?'))) {
if (confirm(this.translate('removeRecordConfirmation', 'messages'))) {
var model = this.collection.get(id);
self.notify('Removing...');
model.destroy({
@@ -62,7 +62,8 @@ Espo.define('Views.Record.Panels.Side', 'View', function (Dep) {
createField: function (field, readOnly) {
var type = this.model.getFieldType(field) || 'base';
this.createView(field, 'Fields.' + Espo.Utils.upperCaseFirst(type), {
var viewName = this.model.getFieldParam(field, 'view') || this.getFieldManager().getViewName(type);
this.createView(field, viewName, {
model: this.model,
el: this.options.el + ' .field-' + field,
defs: {
+1 -1
View File
@@ -200,7 +200,7 @@ Espo.define('Views.Record.Search', 'View', function (Dep) {
},
'click .advanced-filters-bar a[data-action="removePreset"]': function (e) {
var id = $(e.currentTarget).data('id');
if (confirm(this.translate('Are you sure?'))) {
if (confirm(this.translate('confirmation', 'messages'))) {
this.removePreset(id);
}
},
+34
View File
@@ -0,0 +1,34 @@
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
Espo.define('Views.Role.List', 'Views.List', function (Dep) {
return Dep.extend({
searchPanel: false,
setup: function () {
Dep.prototype.setup.call(this);
},
});
});
@@ -0,0 +1,38 @@
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
Espo.define('Views.Role.Record.DetailSide', 'Views.Record.DetailSide', function (Dep) {
return Dep.extend({
panels: [
{
name: 'default',
label: false,
view: 'Role.Record.Panels.Side'
}
],
});
});
@@ -23,7 +23,7 @@ Espo.define('Views.Role.Record.Detail', 'Views.Record.Detail', function (Dep) {
return Dep.extend({
sideView: null,
sideView: 'Role.Record.DetailSide',
editModeEnabled: false,
@@ -23,7 +23,7 @@ Espo.define('Views.Role.Record.Edit', 'Views.Record.Edit', function (Dep) {
return Dep.extend({
sideView: null,
sideView: 'Role.Record.DetailSide',
events: _.extend({
'change select[data-type="access"]': function (e) {

Some files were not shown because too many files have changed in this diff Show More