Compare commits
94 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3df9c7eb02 | |||
| 5951ac930a | |||
| 7160c0a65b | |||
| 19a9b5c91e | |||
| b6d1f26af0 | |||
| 0c10657351 | |||
| 469e35d8a0 | |||
| 977b8fa8e9 | |||
| 7e0604409a | |||
| c21ec8d5f2 | |||
| 41c566e227 | |||
| ae82ebbf74 | |||
| 177018daae | |||
| 5f481fa2dd | |||
| 8c1142481d | |||
| d20a26680a | |||
| 84c56256f7 | |||
| 632467a9a6 | |||
| 2989181723 | |||
| 5df8d833d5 | |||
| 449fc4cddc | |||
| 4e61bd6048 | |||
| 252ae4e18f | |||
| 3def2ef0da | |||
| cb0321aa20 | |||
| 1096f719ae | |||
| ef317064b4 | |||
| fa3b4f3ac2 | |||
| 052c489bf7 | |||
| f3402e2c4e | |||
| 34a3cd9ce5 | |||
| 4d5f3bcbfe | |||
| 339e1dc897 | |||
| c4e617f18e | |||
| 89bc329ea6 | |||
| eee49b215e | |||
| d9a8b83268 | |||
| def7abe3ba | |||
| 75e64b3836 | |||
| efb106c597 | |||
| 5e1087c6b4 | |||
| 5f8800defa | |||
| 445c0b3834 | |||
| 61c1e5ab6c | |||
| 2502cad0c1 | |||
| 76032493b9 | |||
| 0a3a6b3773 | |||
| 014d47d017 | |||
| 8bd7734ae3 | |||
| 7aa2ba917f | |||
| 96f0ce2381 | |||
| f1eb5b9862 | |||
| 45cb5a6e38 | |||
| 4131ea54ae | |||
| 3806affe1b | |||
| 6ea3a03de3 | |||
| 5b25e8b7e6 | |||
| 60c96ba5f7 | |||
| 9732852891 | |||
| 326b46a6e6 | |||
| 29924ea3b1 | |||
| 434506699b | |||
| eeaaaf7af1 | |||
| 3f5dab0680 | |||
| dd69658f2a | |||
| 3c2d998a30 | |||
| a0ead9d774 | |||
| 4460a105a8 | |||
| c6b369587d | |||
| 8c19ad5f7f | |||
| 1824e0d0a6 | |||
| 404bb0c3cd | |||
| 7fd6b16cf3 | |||
| 47abd1ab52 | |||
| 5c8d728ac5 | |||
| 2706bc461e | |||
| 91f52e4f42 | |||
| 5538dd45d3 | |||
| 105205a9aa | |||
| e3547717a0 | |||
| 1714e0e9a0 | |||
| afdd15ac44 | |||
| 09097dba4a | |||
| 01a8fbd5b1 | |||
| f2d5eed7e3 | |||
| cfae3cde1d | |||
| 87a0c1b293 | |||
| 486c8c8f37 | |||
| ea99ca3d38 | |||
| 2069a25f30 | |||
| baf3493044 | |||
| 543a12a475 | |||
| a73f97744a | |||
| ae135ab678 |
@@ -15,7 +15,7 @@ For more information about server configuration see [this article](http://blog.e
|
||||
|
||||
### How to report bug
|
||||
|
||||
Create an issue [here](https://github.com/espocrm/espocrm/issues) or post on our [forum](http://forum.espocrm.com/bug-reports?routestring=forum/bug-reports).
|
||||
Create an issue [here](https://github.com/espocrm/espocrm/issues) or post on our [forum](http://forum.espocrm.com/forum/bug-reports).
|
||||
|
||||
### How to get started (for developers)
|
||||
|
||||
|
||||
@@ -60,11 +60,17 @@ class App extends \Espo\Core\Controllers\Base
|
||||
}
|
||||
$userData['emailAddressList'] = $emailAddressList;
|
||||
|
||||
$settings = (object)[];
|
||||
foreach ($this->getConfig()->get('userItems') as $item) {
|
||||
$settings->$item = $this->getConfig()->get($item);
|
||||
}
|
||||
|
||||
return array(
|
||||
'user' => $userData,
|
||||
'acl' => $this->getAcl()->getMap(),
|
||||
'preferences' => $preferences,
|
||||
'token' => $this->getUser()->get('token')
|
||||
'token' => $this->getUser()->get('token'),
|
||||
'settings' => $settings
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -40,32 +40,32 @@ class AuthToken extends \Espo\Core\Controllers\Record
|
||||
}
|
||||
}
|
||||
|
||||
public function actionUpdate($params, $data)
|
||||
public function actionUpdate($params, $data, $request)
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionCreate($params, $data)
|
||||
public function actionCreate($params, $data, $request)
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionListLinked($params, $data)
|
||||
public function actionListLinked($params, $data, $request)
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionMassUpdate($params, $data)
|
||||
public function actionMassUpdate($params, $data, $request)
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionCreateLink($params, $data)
|
||||
public function actionCreateLink($params, $data, $request)
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionRemoveLink($params, $data)
|
||||
public function actionRemoveLink($params, $data, $request)
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
@@ -67,6 +67,19 @@ class Integration extends \Espo\Core\Controllers\Record
|
||||
$entity->set($data);
|
||||
$this->getEntityManager()->saveEntity($entity);
|
||||
|
||||
$integrationsConfigData = $this->getConfig()->get('integrations');
|
||||
|
||||
if (!$integrationsConfigData || !($integrationsConfigData instanceof \StdClass)) {
|
||||
$integrationsConfigData = (object)[];
|
||||
}
|
||||
$integrationName = $params['id'];
|
||||
|
||||
$integrationsConfigData->$integrationName = $entity->get('enabled');
|
||||
$this->getConfig()->set('integrations', $integrationsConfigData);
|
||||
|
||||
$this->getConfig()->save();
|
||||
|
||||
|
||||
return $entity->toArray();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,11 @@ class Settings extends \Espo\Core\Controllers\Base
|
||||
{
|
||||
protected function getConfigData()
|
||||
{
|
||||
$data = $this->getConfig()->getData($this->getUser()->isAdmin());
|
||||
if ($this->getUser()->id == 'system') {
|
||||
$data = $this->getConfig()->getData();
|
||||
} else {
|
||||
$data = $this->getConfig()->getData($this->getUser()->isAdmin());
|
||||
}
|
||||
|
||||
$fieldDefs = $this->getMetadata()->get('entityDefs.Settings.fields');
|
||||
|
||||
|
||||
@@ -283,7 +283,7 @@ class Container
|
||||
\Espo\Core\Utils\Language::detectLanguage($this->get('config'), $this->get('preferences')),
|
||||
$this->get('fileManager'),
|
||||
$this->get('metadata'),
|
||||
$this->get('useCache')
|
||||
$this->get('config')->get('useCache')
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -159,7 +159,15 @@ class Htmlizer
|
||||
|
||||
public function render(Entity $entity, $template, $id = null, $additionalData = array(), $skipLinks = false)
|
||||
{
|
||||
$code = \LightnCandy::compile($template);
|
||||
$code = \LightnCandy::compile($template, [
|
||||
'helpers' => [
|
||||
'file' => function ($context, $options) {
|
||||
if (count($context) && $context[0]) {
|
||||
return 'data/upload/'.$context[0];
|
||||
}
|
||||
}
|
||||
]
|
||||
]);
|
||||
|
||||
$toRemove = false;
|
||||
if ($id === null) {
|
||||
|
||||
@@ -273,18 +273,6 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
|
||||
$entity->set('createdById', $this->getEntityManager()->getUser()->id);
|
||||
}
|
||||
}
|
||||
|
||||
if ($entity->has('modifiedById')) {
|
||||
$restoreData['modifiedById'] = $entity->get('modifiedById');
|
||||
}
|
||||
if ($entity->has('modifiedByName')) {
|
||||
$restoreData['modifiedByName'] = $entity->get('modifiedByName');
|
||||
}
|
||||
if ($entity->has('modifiedAt')) {
|
||||
$restoreData['modifiedAt'] = $entity->get('modifiedAt');
|
||||
}
|
||||
$entity->clear('modifiedById');
|
||||
$entity->clear('modifiedByName');
|
||||
} else {
|
||||
if (empty($options['silent'])) {
|
||||
if ($entity->hasAttribute('modifiedAt')) {
|
||||
@@ -295,20 +283,6 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
|
||||
$entity->set('modifiedByName', $this->getEntityManager()->getUser()->get('name'));
|
||||
}
|
||||
}
|
||||
|
||||
if ($entity->has('createdById')) {
|
||||
if (empty($options['import'])) {
|
||||
$restoreData['createdById'] = $entity->get('createdById');
|
||||
$entity->clear('createdById');
|
||||
}
|
||||
}
|
||||
|
||||
if ($entity->has('createdAt')) {
|
||||
if (empty($options['import'])) {
|
||||
$restoreData['createdAt'] = $entity->get('createdAt');
|
||||
$entity->clear('createdAt');
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->restoreData = $restoreData;
|
||||
|
||||
|
||||
@@ -29,7 +29,14 @@
|
||||
|
||||
namespace Espo\Core\Templates\Services;
|
||||
|
||||
use \Espo\ORM\Entity;
|
||||
|
||||
class Company extends \Espo\Services\Record
|
||||
{
|
||||
|
||||
protected function getDuplicateWhereClause(Entity $entity, $data = array())
|
||||
{
|
||||
return array(
|
||||
'name' => $entity->get('name')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
namespace Espo\Core\Templates\Services;
|
||||
|
||||
use \Espo\ORM\Entity;
|
||||
|
||||
class Person extends \Espo\Services\Record
|
||||
{
|
||||
|
||||
@@ -226,7 +226,7 @@ class Config
|
||||
* @param $isAdmin
|
||||
* @return array
|
||||
*/
|
||||
public function getData($isAdmin = false)
|
||||
public function getData($isAdmin = null)
|
||||
{
|
||||
$data = $this->loadConfig();
|
||||
|
||||
@@ -247,7 +247,7 @@ class Config
|
||||
* @param $isAdmin
|
||||
* @return bool
|
||||
*/
|
||||
public function setData($data, $isAdmin = false)
|
||||
public function setData($data, $isAdmin = null)
|
||||
{
|
||||
$restrictItems = $this->getRestrictItems($isAdmin);
|
||||
|
||||
@@ -285,7 +285,7 @@ class Config
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
protected function getRestrictItems($onlySystemItems = false)
|
||||
protected function getRestrictItems($onlySystemItems = null)
|
||||
{
|
||||
$data = $this->loadConfig();
|
||||
|
||||
@@ -297,7 +297,11 @@ class Config
|
||||
$this->adminItems = array_merge($data['systemItems'], $data['adminItems']);
|
||||
}
|
||||
|
||||
return $this->adminItems;
|
||||
if ($onlySystemItems === false) {
|
||||
return $this->adminItems;
|
||||
}
|
||||
|
||||
return array_merge($this->adminItems, $data['userItems']);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -49,6 +49,8 @@ class EntityManager
|
||||
|
||||
private $container;
|
||||
|
||||
private $reservedWordList = ['__halt_compiler', 'abstract', 'and', 'array', 'as', 'break', 'callable', 'case', 'catch', 'class', 'clone', 'const', 'continue', 'declare', 'default', 'die', 'do', 'echo', 'else', 'elseif', 'empty', 'enddeclare', 'endfor', 'endforeach', 'endif', 'endswitch', 'endwhile', 'eval', 'exit', 'extends', 'final', 'for', 'foreach', 'function', 'global', 'goto', 'if', 'implements', 'include', 'include_once', 'instanceof', 'insteadof', 'interface', 'isset', 'list', 'namespace', 'new', 'or', 'print', 'private', 'protected', 'public', 'require', 'require_once', 'return', 'static', 'switch', 'throw', 'trait', 'try', 'unset', 'use', 'var', 'while', 'xor'];
|
||||
|
||||
public function __construct(Metadata $metadata, Language $language, File\Manager $fileManager, Config $config, Container $container = null)
|
||||
{
|
||||
$this->metadata = $metadata;
|
||||
@@ -86,16 +88,33 @@ class EntityManager
|
||||
return $this->metadataHelper;
|
||||
}
|
||||
|
||||
protected function getServiceFactory()
|
||||
{
|
||||
if (!$this->container) return;
|
||||
|
||||
return $this->container->get('serviceFactory');
|
||||
}
|
||||
|
||||
public function create($name, $type, $params = array())
|
||||
{
|
||||
$name = ucfirst($name);
|
||||
$name = trim($name);
|
||||
|
||||
if ($this->getMetadata()->get('scopes.' . $name)) {
|
||||
throw new Conflict('Entity ['.$name.'] already exists.');
|
||||
throw new Conflict('Entity \''.$name.'\' already exists.');
|
||||
}
|
||||
if (empty($name) || empty($type)) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
$name = trim($name);
|
||||
$serviceFactory = $this->getServiceFactory();
|
||||
if ($serviceFactory && $serviceFactory->checKExists($name)) {
|
||||
throw new Conflict('Entity name \''.$name.'\' is not allowed.');
|
||||
}
|
||||
|
||||
if (in_array(strtolower($name), $this->reservedWordList)) {
|
||||
throw new Conflict('Entity name \''.$name.'\' is not allowed.');
|
||||
}
|
||||
|
||||
$normalizedName = Util::normilizeClassName($name);
|
||||
|
||||
|
||||
@@ -123,7 +123,13 @@ class FieldManager
|
||||
|
||||
if ($this->getMetadata()->get(['fields', $type, 'translatedOptions'])) {
|
||||
if (isset($fieldDefs['translatedOptions'])) {
|
||||
$this->setTranslatedOptions($name, $fieldDefs['translatedOptions'], $scope);
|
||||
$translatedOptions = $fieldDefs['translatedOptions'];
|
||||
$translatedOptions = json_decode(json_encode($fieldDefs['translatedOptions']), true);
|
||||
if (isset($translatedOptions['_empty_'])) {
|
||||
$translatedOptions[''] = $translatedOptions['_empty_'];
|
||||
}
|
||||
|
||||
$this->setTranslatedOptions($name, $translatedOptions, $scope);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -625,12 +625,19 @@ class Manager
|
||||
$items = (array) $items;
|
||||
}
|
||||
|
||||
$removeList = array();
|
||||
$permissionDeniedList = array();
|
||||
foreach ($items as $item) {
|
||||
if (isset($dirPath)) {
|
||||
$item = Utils\Util::concatPath($dirPath, $item);
|
||||
}
|
||||
|
||||
if (!file_exists($item)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$removeList[] = $item;
|
||||
|
||||
if (!is_writable($item)) {
|
||||
$permissionDeniedList[] = $item;
|
||||
} else if (!is_writable(dirname($item))) {
|
||||
@@ -644,11 +651,7 @@ class Manager
|
||||
}
|
||||
|
||||
$result = true;
|
||||
foreach ($items as $item) {
|
||||
if (isset($dirPath)) {
|
||||
$item = Utils\Util::concatPath($dirPath, $item);
|
||||
}
|
||||
|
||||
foreach ($removeList as $item) {
|
||||
if (is_dir($item)) {
|
||||
$result &= $this->removeInDir($item, true);
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
|
||||
}
|
||||
@@ -94,7 +94,8 @@ return array ( 'defaultPermissions' =>
|
||||
'restrictedMode',
|
||||
'userLimit',
|
||||
'portalUserLimit',
|
||||
'stylesheet'
|
||||
'stylesheet',
|
||||
'userItems'
|
||||
),
|
||||
'adminItems' =>
|
||||
array (
|
||||
@@ -137,7 +138,18 @@ return array ( 'defaultPermissions' =>
|
||||
'personalEmailMaxPortionSize',
|
||||
'inboundEmailMaxPortionSize',
|
||||
'authTokenLifetime',
|
||||
'authTokenMaxIdleTime'
|
||||
'authTokenMaxIdleTime',
|
||||
'ldapUserDefaultTeamId',
|
||||
'ldapUserDefaultTeamName',
|
||||
'ldapUserTeamsIds',
|
||||
'ldapUserTeamsNames'
|
||||
),
|
||||
'userItems' =>
|
||||
array (
|
||||
'outboundEmailFromAddress',
|
||||
'outboundEmailFromName',
|
||||
'integrations',
|
||||
'googleMapsApiKey'
|
||||
),
|
||||
'isInstalled' => false,
|
||||
'ldapUserNameAttribute' => 'sAMAccountName',
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
"presetFilters": {
|
||||
"actual": "Aktuell",
|
||||
"completed": "Abgeschlossen",
|
||||
"deferred": "Zurückgestellt",
|
||||
"todays": "Heutige",
|
||||
"overdue": "Überfällig"
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
"Culture": "Culture",
|
||||
"Education": "Education",
|
||||
"Electronics": "Electronics",
|
||||
"Electric Power": "Electric Power",
|
||||
"Energy": "Energy",
|
||||
"Entertainment & Leisure": "Entertainment & Leisure",
|
||||
"Finance": "Finance",
|
||||
@@ -67,11 +68,14 @@
|
||||
"Legal": "Legal",
|
||||
"Manufacturing": "Manufacturing",
|
||||
"Mass Media": "Mass Media",
|
||||
"Mining": "Mining",
|
||||
"Music": "Music",
|
||||
"Marketing": "Marketing",
|
||||
"Publishing": "Publishing",
|
||||
"Petroleum": "Petroleum",
|
||||
"Real Estate": "Real Estate",
|
||||
"Retail": "Retail",
|
||||
"Shipping": "Shipping",
|
||||
"Service": "Service",
|
||||
"Support": "Support",
|
||||
"Sports": "Sports",
|
||||
@@ -79,6 +83,7 @@
|
||||
"Technology": "Technology",
|
||||
"Telecommunications": "Telecommunications",
|
||||
"Television": "Television",
|
||||
"Testing, Inspection & Certification": "Testing, Inspection & Certification",
|
||||
"Transportation": "Transportation",
|
||||
"Venture Capital": "Venture Capital",
|
||||
"Wholesale": "Wholesale",
|
||||
|
||||
@@ -45,5 +45,8 @@
|
||||
"planned": "Planned",
|
||||
"held": "Held",
|
||||
"todays": "Today's"
|
||||
},
|
||||
"messages": {
|
||||
"nothingHasBeenSent": "Nothing were sent"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
"presetFilters": {
|
||||
"actual": "Actual",
|
||||
"completed": "Completed",
|
||||
"deferred": "Deferred",
|
||||
"todays": "Today's",
|
||||
"overdue": "Overdue"
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
"presetFilters": {
|
||||
"actual": "Actuales",
|
||||
"completed": "Completado",
|
||||
"deferred": "Diferido",
|
||||
"todays": "De Hoy",
|
||||
"overdue": "Atrazadas"
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
"actual": "En cours",
|
||||
"completed": "Terminés",
|
||||
"todays": "Aujourd'hui",
|
||||
"deferred": "Reporté",
|
||||
"overdue": "En retard"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
"actual": "Sebenarnya",
|
||||
"completed": "Lengkap",
|
||||
"todays": "hari ini",
|
||||
"deferred": "Tangguhan",
|
||||
"overdue": "Terlambat"
|
||||
}
|
||||
}
|
||||
@@ -40,6 +40,7 @@
|
||||
"actual": "Attuale",
|
||||
"completed": "Completato",
|
||||
"todays": "Di Oggi",
|
||||
"deferred": "Prorogare",
|
||||
"overdue": "In RItardo"
|
||||
}
|
||||
}
|
||||
@@ -22,8 +22,7 @@
|
||||
"Not Started": "Niet Gestart",
|
||||
"Started": "Gestart",
|
||||
"Completed": "Voltooid",
|
||||
"Canceled": "Geannuleerd",
|
||||
"Deferred": "Deferred"
|
||||
"Canceled": "Geannuleerd"
|
||||
},
|
||||
"priority" : {
|
||||
"Low": "Laag",
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
"presetFilters": {
|
||||
"actual": "Bieżący",
|
||||
"completed": "Ukończone",
|
||||
"deferred": "Opóźniony",
|
||||
"todays": "Dzisiaj",
|
||||
"overdue": "Przegrzane"
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
"actual": "Atual",
|
||||
"completed": "Completa",
|
||||
"todays": "Hoje",
|
||||
"deferred": "Adiada",
|
||||
"overdue": "Atrasada"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
"actual": "Актуальные",
|
||||
"completed": "Завершенные",
|
||||
"todays": "На сегодня",
|
||||
"deferred": "Отложенные",
|
||||
"overdue": "Просроченные"
|
||||
}
|
||||
}
|
||||
@@ -37,9 +37,10 @@
|
||||
"Complete": "Завершити"
|
||||
},
|
||||
"presetFilters": {
|
||||
"actual": "Актуально",
|
||||
"completed": "Завершено",
|
||||
"todays": "Сьогоднішнє",
|
||||
"overdue": "Прострочено"
|
||||
"actual": "Актуальні",
|
||||
"completed": "Завершені",
|
||||
"todays": "Сьогоднішні",
|
||||
"deferred": "Відстрочені",
|
||||
"overdue": "Прострочені"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"activities": {
|
||||
"disabled": true
|
||||
},
|
||||
"history": {
|
||||
"disabled": true
|
||||
},
|
||||
"tasks": {
|
||||
"disabled": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"activities": {
|
||||
"disabled": true
|
||||
},
|
||||
"history": {
|
||||
"disabled": true
|
||||
},
|
||||
"tasks": {
|
||||
"disabled": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"activities": {
|
||||
"disabled": true
|
||||
},
|
||||
"history": {
|
||||
"disabled": true
|
||||
},
|
||||
"tasks": {
|
||||
"disabled": true
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
"rows": [
|
||||
[{"name":"status"},{"name":"source"}],
|
||||
[{"name":"opportunityAmount"},{"name":"campaign"}],
|
||||
[false, {"name":"industry"}],
|
||||
[{"name":"industry"}, false],
|
||||
[{"name":"description", "fullWidth": true}]
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"activities": {
|
||||
"disabled": true
|
||||
},
|
||||
"history": {
|
||||
"disabled": true
|
||||
},
|
||||
"tasks": {
|
||||
"disabled": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"activities": {
|
||||
"disabled": true
|
||||
},
|
||||
"history": {
|
||||
"disabled": true
|
||||
},
|
||||
"tasks": {
|
||||
"disabled": true
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,26 @@
|
||||
"view":"crm:views/record/panels/tasks",
|
||||
"aclScope": "Task"
|
||||
}
|
||||
],
|
||||
"detailSmall": [
|
||||
{
|
||||
"name":"activities",
|
||||
"label":"Activities",
|
||||
"view":"crm:views/record/panels/activities",
|
||||
"aclScope": "Activities"
|
||||
},
|
||||
{
|
||||
"name":"history",
|
||||
"label":"History",
|
||||
"view":"crm:views/record/panels/history",
|
||||
"aclScope": "Activities"
|
||||
},
|
||||
{
|
||||
"name":"tasks",
|
||||
"label":"Tasks",
|
||||
"view":"crm:views/record/panels/tasks",
|
||||
"aclScope": "Task"
|
||||
}
|
||||
]
|
||||
},
|
||||
"relationshipPanels": {
|
||||
|
||||
@@ -3,10 +3,6 @@
|
||||
"recordViews": {
|
||||
"detail": "crm:views/case/record/detail"
|
||||
},
|
||||
"bottomPanels":{
|
||||
"detail":[
|
||||
]
|
||||
},
|
||||
"sidePanels":{
|
||||
"detail":[
|
||||
{
|
||||
@@ -27,6 +23,26 @@
|
||||
"view":"crm:views/record/panels/tasks",
|
||||
"aclScope": "Task"
|
||||
}
|
||||
],
|
||||
"detailSmall":[
|
||||
{
|
||||
"name":"activities",
|
||||
"label":"Activities",
|
||||
"view":"crm:views/case/record/panels/activities",
|
||||
"aclScope": "Activities"
|
||||
},
|
||||
{
|
||||
"name":"history",
|
||||
"label":"History",
|
||||
"view":"crm:views/record/panels/history",
|
||||
"aclScope": "Activities"
|
||||
},
|
||||
{
|
||||
"name":"tasks",
|
||||
"label":"Tasks",
|
||||
"view":"crm:views/record/panels/tasks",
|
||||
"aclScope": "Task"
|
||||
}
|
||||
]
|
||||
},
|
||||
"filterList": [
|
||||
|
||||
@@ -4,6 +4,34 @@
|
||||
"views":{
|
||||
"detail":"crm:views/contact/detail"
|
||||
},
|
||||
"recordViews":{
|
||||
"detail": "crm:views/contact/record/detail",
|
||||
"detailQuick": "crm:views/contact/record/detail-small"
|
||||
},
|
||||
"defaultSidePanelFieldList": {
|
||||
"detail": [
|
||||
{
|
||||
"name": "assignedUser"
|
||||
},
|
||||
{
|
||||
"name": "teams"
|
||||
},
|
||||
{
|
||||
"name": "portalUser"
|
||||
}
|
||||
],
|
||||
"detailSmall": [
|
||||
{
|
||||
"name": "assignedUser"
|
||||
},
|
||||
{
|
||||
"name": "teams"
|
||||
},
|
||||
{
|
||||
"name": "portalUser"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sidePanels":{
|
||||
"detail":[
|
||||
{
|
||||
@@ -24,6 +52,26 @@
|
||||
"view":"crm:views/record/panels/tasks",
|
||||
"aclScope": "Task"
|
||||
}
|
||||
],
|
||||
"detailSmall":[
|
||||
{
|
||||
"name":"activities",
|
||||
"label":"Activities",
|
||||
"view":"crm:views/record/panels/activities",
|
||||
"aclScope": "Activities"
|
||||
},
|
||||
{
|
||||
"name":"history",
|
||||
"label":"History",
|
||||
"view":"crm:views/record/panels/history",
|
||||
"aclScope": "Activities"
|
||||
},
|
||||
{
|
||||
"name":"tasks",
|
||||
"label":"Tasks",
|
||||
"view":"crm:views/record/panels/tasks",
|
||||
"aclScope": "Task"
|
||||
}
|
||||
]
|
||||
},
|
||||
"relationshipPanels": {
|
||||
|
||||
@@ -31,7 +31,8 @@
|
||||
"label":"Converted To",
|
||||
"view": "crm:views/lead/record/panels/converted-to",
|
||||
"notRefreshable": true,
|
||||
"hidden": true
|
||||
"hidden": true,
|
||||
"style": "success"
|
||||
},
|
||||
{
|
||||
"name":"activities",
|
||||
@@ -58,7 +59,8 @@
|
||||
"label":"Converted To",
|
||||
"view": "crm:views/lead/record/panels/converted-to",
|
||||
"notRefreshable": true,
|
||||
"hidden": true
|
||||
"hidden": true,
|
||||
"style": "success"
|
||||
}
|
||||
],
|
||||
"detailSmall": [
|
||||
@@ -67,7 +69,26 @@
|
||||
"label":"Converted To",
|
||||
"view": "crm:views/lead/record/panels/converted-to",
|
||||
"notRefreshable": true,
|
||||
"hidden": true
|
||||
"hidden": true,
|
||||
"style": "success"
|
||||
},
|
||||
{
|
||||
"name":"activities",
|
||||
"label":"Activities",
|
||||
"view":"crm:views/record/panels/activities",
|
||||
"aclScope": "Activities"
|
||||
},
|
||||
{
|
||||
"name":"history",
|
||||
"label":"History",
|
||||
"view":"crm:views/record/panels/history",
|
||||
"aclScope": "Activities"
|
||||
},
|
||||
{
|
||||
"name":"tasks",
|
||||
"label":"Tasks",
|
||||
"view":"crm:views/record/panels/tasks",
|
||||
"aclScope": "Task"
|
||||
}
|
||||
],
|
||||
"editSmall": [
|
||||
@@ -76,7 +97,8 @@
|
||||
"label":"Converted To",
|
||||
"view": "crm:views/lead/record/panels/converted-to",
|
||||
"notRefreshable": true,
|
||||
"hidden": true
|
||||
"hidden": true,
|
||||
"style": "success"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -1,54 +1,75 @@
|
||||
{
|
||||
"controller": "controllers/record",
|
||||
"acl": "crm:acl/mass-email",
|
||||
"recordViews": {
|
||||
"detail": "crm:views/mass-email/record/detail",
|
||||
"edit": "crm:views/mass-email/record/edit",
|
||||
"editQuick": "crm:views/mass-email/record/edit-small"
|
||||
},
|
||||
"views": {
|
||||
"detail": "crm:views/mass-email/detail"
|
||||
},
|
||||
"defaultSidePanel": {
|
||||
"edit": false,
|
||||
"editSmall": false
|
||||
},
|
||||
"formDependency": {
|
||||
"status": {
|
||||
"map": {
|
||||
"Complete": [
|
||||
{
|
||||
"action": "setReadOnly",
|
||||
"fields": [
|
||||
"status"
|
||||
"controller": "controllers/record",
|
||||
"acl": "crm:acl/mass-email",
|
||||
"recordViews": {
|
||||
"detail": "crm:views/mass-email/record/detail",
|
||||
"edit": "crm:views/mass-email/record/edit",
|
||||
"editQuick": "crm:views/mass-email/record/edit-small"
|
||||
},
|
||||
"views": {
|
||||
"detail": "crm:views/mass-email/detail"
|
||||
},
|
||||
"defaultSidePanel": {
|
||||
"edit": false,
|
||||
"editSmall": false
|
||||
},
|
||||
"dynamicLogic": {
|
||||
"fields": {
|
||||
"status": {
|
||||
"readOnly": {
|
||||
"conditionGroup": [
|
||||
{
|
||||
"type": "and",
|
||||
"value": [
|
||||
{
|
||||
"type": "or",
|
||||
"value": [
|
||||
{
|
||||
"type": "equals",
|
||||
"attribute": "status",
|
||||
"value": "Complete"
|
||||
},
|
||||
{
|
||||
"type": "equals",
|
||||
"attribute": "status",
|
||||
"value": "In Process"
|
||||
},
|
||||
{
|
||||
"type": "equals",
|
||||
"attribute": "status",
|
||||
"value": "Failed"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "isNotEmpty",
|
||||
"attribute": "id"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"status": [
|
||||
{
|
||||
"optionList": [
|
||||
"Draft",
|
||||
"Pending"
|
||||
],
|
||||
"conditionGroup": [
|
||||
{
|
||||
"type": "in",
|
||||
"attribute": "status",
|
||||
"value": [
|
||||
"Draft",
|
||||
"Pending"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"In Process": [
|
||||
{
|
||||
"action": "setReadOnly",
|
||||
"fields": [
|
||||
"status"
|
||||
]
|
||||
}
|
||||
],
|
||||
"Failed": [
|
||||
{
|
||||
"action": "setReadOnly",
|
||||
"fields": [
|
||||
"status"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": [
|
||||
{
|
||||
"action": "setNotReadOnly",
|
||||
"fields": [
|
||||
"status"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"controller": "controllers/record",
|
||||
"views":{
|
||||
"detail":"Crm:Opportunity.Detail"
|
||||
"detail":"crm:views/opportunity/detail"
|
||||
},
|
||||
"sidePanels":{
|
||||
"detail":[
|
||||
@@ -23,6 +23,26 @@
|
||||
"view":"crm:views/record/panels/tasks",
|
||||
"aclScope": "Task"
|
||||
}
|
||||
],
|
||||
"detailSmall":[
|
||||
{
|
||||
"name":"activities",
|
||||
"label":"Activities",
|
||||
"view":"crm:views/record/panels/activities",
|
||||
"aclScope": "Activities"
|
||||
},
|
||||
{
|
||||
"name":"history",
|
||||
"label":"History",
|
||||
"view":"crm:views/record/panels/history",
|
||||
"aclScope": "Activities"
|
||||
},
|
||||
{
|
||||
"name":"tasks",
|
||||
"label":"Tasks",
|
||||
"view":"crm:views/record/panels/tasks",
|
||||
"aclScope": "Task"
|
||||
}
|
||||
]
|
||||
},
|
||||
"filterList": [
|
||||
|
||||
@@ -55,6 +55,9 @@
|
||||
{
|
||||
"name":"overdue",
|
||||
"style": "danger"
|
||||
},
|
||||
{
|
||||
"name":"deferred"
|
||||
}
|
||||
],
|
||||
"boolFilterList": ["onlyMy"]
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
"bool": {
|
||||
"onlyMy": true
|
||||
},
|
||||
"primary": "actualNotDeferred"
|
||||
"primary": "actualStartingNotInPast"
|
||||
}
|
||||
},
|
||||
"layout": [
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
"Defense",
|
||||
"Education",
|
||||
"Electronics",
|
||||
"Electric Power",
|
||||
"Energy",
|
||||
"Entertainment & Leisure",
|
||||
"Finance",
|
||||
@@ -54,18 +55,22 @@
|
||||
"Manufacturing",
|
||||
"Mass Media",
|
||||
"Marketing",
|
||||
"Mining",
|
||||
"Music",
|
||||
"Publishing",
|
||||
"Petroleum",
|
||||
"Real Estate",
|
||||
"Retail",
|
||||
"Service",
|
||||
"Sports",
|
||||
"Software",
|
||||
"Support",
|
||||
"Shipping",
|
||||
"Technology",
|
||||
"Telecommunications",
|
||||
"Television",
|
||||
"Transportation",
|
||||
"Testing, Inspection & Certification",
|
||||
"Venture Capital",
|
||||
"Wholesale",
|
||||
"Water"
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
},
|
||||
"object": {
|
||||
"type": "belongsToParent",
|
||||
"entityList": ["Email"]
|
||||
"entityList": ["Email", "CampaignTrackingUrl"]
|
||||
}
|
||||
},
|
||||
"collection": {
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
"type": {
|
||||
"type": "enum",
|
||||
"options": ["", "Question", "Incident", "Problem"],
|
||||
"default": "",
|
||||
"audited": true
|
||||
},
|
||||
"description": {
|
||||
|
||||
@@ -182,6 +182,7 @@
|
||||
"type": "link",
|
||||
"layoutMassUpdateDisabled": true,
|
||||
"layoutListDisabled": true,
|
||||
"layoutDetailDisabled": true,
|
||||
"readOnly": true,
|
||||
"notStorable": true,
|
||||
"view": "views/fields/link-one"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
},
|
||||
"status": {
|
||||
"type": "enum",
|
||||
"options": ["Draft", "Pending"],
|
||||
"options": ["Draft", "Pending", "Complete", "In Process", "Failed"],
|
||||
"default": "Pending"
|
||||
},
|
||||
"storeSentEmails": {
|
||||
|
||||
@@ -110,7 +110,8 @@
|
||||
},
|
||||
"assignedUser": {
|
||||
"type": "belongsTo",
|
||||
"entity": "User"
|
||||
"entity": "User",
|
||||
"foreign": "tasks"
|
||||
},
|
||||
"teams": {
|
||||
"type": "hasMany",
|
||||
|
||||
@@ -44,11 +44,18 @@ class Task extends \Espo\Core\SelectManagers\Base
|
||||
protected function filterActual(&$result)
|
||||
{
|
||||
$result['whereClause'][] = array(
|
||||
'status!=' => ['Completed', 'Canceled']
|
||||
'status!=' => ['Completed', 'Canceled', 'Deferred']
|
||||
);
|
||||
}
|
||||
|
||||
protected function filterActualNotDeferred(&$result)
|
||||
protected function filterDeferred(&$result)
|
||||
{
|
||||
$result['whereClause'][] = array(
|
||||
'status=' => 'Deferred'
|
||||
);
|
||||
}
|
||||
|
||||
protected function filterActualStartingNotInPast(&$result)
|
||||
{
|
||||
$result['whereClause'][] = array(
|
||||
array(
|
||||
|
||||
@@ -138,11 +138,19 @@ class Meeting extends \Espo\Services\Record
|
||||
|
||||
$emailHash = array();
|
||||
|
||||
$sentCount = 0;
|
||||
|
||||
$users = $entity->get('users');
|
||||
foreach ($users as $user) {
|
||||
if ($user->id === $this->getUser()->id) {
|
||||
if ($entity->getLinkMultipleColumn('users', 'status', $user->id) === 'Accepted') {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ($user->get('emailAddress') && !array_key_exists($user->get('emailAddress'), $emailHash)) {
|
||||
$invitationManager->sendInvitation($entity, $user, 'users');
|
||||
$emailHash[$user->get('emailAddress')] = true;
|
||||
$sentCount ++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,6 +159,7 @@ class Meeting extends \Espo\Services\Record
|
||||
if ($contact->get('emailAddress') && !array_key_exists($contact->get('emailAddress'), $emailHash)) {
|
||||
$invitationManager->sendInvitation($entity, $contact, 'contacts');
|
||||
$emailHash[$user->get('emailAddress')] = true;
|
||||
$sentCount ++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,9 +168,12 @@ class Meeting extends \Espo\Services\Record
|
||||
if ($lead->get('emailAddress') && !array_key_exists($lead->get('emailAddress'), $emailHash)) {
|
||||
$invitationManager->sendInvitation($entity, $lead, 'leads');
|
||||
$emailHash[$user->get('emailAddress')] = true;
|
||||
$sentCount ++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$sentCount) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,9 @@
|
||||
"massUpdate": "Mass Update",
|
||||
"relationships": "Relationship Panels",
|
||||
"sidePanelsDetail": "Side Panels (Detail)",
|
||||
"sidePanelsEdit": "Side Panels (Edit)"
|
||||
"sidePanelsEdit": "Side Panels (Edit)",
|
||||
"sidePanelsDetailSmall": "Side Panels (Detail Small)",
|
||||
"sidePanelsEditSmall": "Side Panels (Edit Small)"
|
||||
},
|
||||
"fieldTypes": {
|
||||
"address": "Address",
|
||||
|
||||
@@ -191,7 +191,7 @@
|
||||
"posting": "Posting...",
|
||||
"confirmLeaveOutMessage": "Are you sure you want to leave the form?",
|
||||
"notModified": "You have not modified the record",
|
||||
"duplicate": "The record you are creating seems to be a duplicate",
|
||||
"duplicate": "The record you are creating might already exist",
|
||||
"dropToAttach": "Drop to attach",
|
||||
"fieldIsRequired": "{field} is required",
|
||||
"fieldShouldBeEmail": "{field} should be valid email",
|
||||
|
||||
@@ -3,12 +3,23 @@
|
||||
"width": "Width (%)",
|
||||
"link": "Link",
|
||||
"notSortable": "Not Sortable",
|
||||
"align": "Align"
|
||||
"align": "Align",
|
||||
"panelName": "Panel Name",
|
||||
"style": "Style",
|
||||
"sticked": "Sticked"
|
||||
},
|
||||
"options": {
|
||||
"align": {
|
||||
"left": "Left",
|
||||
"right": "Right"
|
||||
},
|
||||
"style": {
|
||||
"default": "Default",
|
||||
"success": "Success",
|
||||
"danger": "Danger",
|
||||
"info": "Info",
|
||||
"warning": "Warning",
|
||||
"primary": "Primary"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +84,8 @@
|
||||
"mentionEmailNotifications": "Send email notifications about mentions in posts",
|
||||
"massEmailDisableMandatoryOptOutLink": "Disable mandatory opt-out link",
|
||||
"activitiesEntityList": "Activities Entity List",
|
||||
"historyEntityList": "History Entity List"
|
||||
"historyEntityList": "History Entity List",
|
||||
"b2cMode": "B2C Mode"
|
||||
},
|
||||
"options": {
|
||||
"weekStart": {
|
||||
@@ -121,7 +122,8 @@
|
||||
"ldapAccountDomainName": "The domain which is used for authorization to LDAP server.",
|
||||
"ldapAccountDomainNameShort": "The short domain which is used for authorization to LDAP server.",
|
||||
"ldapUserTeams": "Teams for created user. For more, see user profile.",
|
||||
"ldapUserDefaultTeam": "Default team for created user. For more, see user profile."
|
||||
"ldapUserDefaultTeam": "Default team for created user. For more, see user profile.",
|
||||
"b2cMode": "By default EspoCRM is adapted for B2B. You can switch it to B2C."
|
||||
},
|
||||
"labels": {
|
||||
"System": "System",
|
||||
|
||||
@@ -35,7 +35,8 @@
|
||||
"portalRoles": "Portal Roles",
|
||||
"contact": "Contact",
|
||||
"accounts": "Accounts",
|
||||
"account": "Account (Primary)"
|
||||
"account": "Account (Primary)",
|
||||
"tasks": "Tasks"
|
||||
},
|
||||
"labels": {
|
||||
"Create User": "Create User",
|
||||
@@ -67,7 +68,7 @@
|
||||
"accountInfoEmailSubject": "EspoCRM User Access Info",
|
||||
"accountInfoEmailBody": "Your access information:\n\nUsername: {userName}\nPassword: {password}\n\n{siteUrl}",
|
||||
"passwordChangeLinkEmailSubject": "Change Password Request",
|
||||
"passwordChangeLinkEmailBody": "You can change your password by this link {link}. This unique url will be exprired soon.",
|
||||
"passwordChangeLinkEmailBody": "You can change your password by this link {link}. This unique url will be expired soon.",
|
||||
"passwordChanged": "Password has been changed",
|
||||
"userCantBeEmpty": "Username can not be empty",
|
||||
"wrongUsernamePasword": "Wrong username/password",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"rows": [
|
||||
[{"name": "useCache"}, {"name": "siteUrl"}],
|
||||
[{"name": "exportDisabled"}, {"name": "globalSearchEntityList"}],
|
||||
[{"name": "followCreatedEntities"}, false]
|
||||
[{"name": "followCreatedEntities"}, {"name": "b2cMode"}]
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"activities": {
|
||||
"disabled": true
|
||||
},
|
||||
"history": {
|
||||
"disabled": true
|
||||
},
|
||||
"tasks": {
|
||||
"disabled": true
|
||||
}
|
||||
}
|
||||
@@ -129,6 +129,10 @@
|
||||
"linkMultiple": {
|
||||
"view": "views/admin/dynamic-logic/conditions/field-types/link-multiple",
|
||||
"typeList": ["isEmpty", "isNotEmpty", "contains", "notContains"]
|
||||
},
|
||||
"id": {
|
||||
"view": "views/admin/dynamic-logic/conditions/field-types/base",
|
||||
"typeList": ["isEmpty", "isNotEmpty"]
|
||||
}
|
||||
},
|
||||
"conditionTypes": {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"controller": "controllers/record",
|
||||
"recordViews": {
|
||||
"detail": "Template.Record.Detail"
|
||||
"detail": "views/template/record/detail",
|
||||
"edit": "views/template/record/edit"
|
||||
},
|
||||
"formDependency": {
|
||||
"printFooter": {
|
||||
|
||||
@@ -10,6 +10,62 @@
|
||||
"editQuick":"views/user/record/edit-quick",
|
||||
"list":"views/user/record/list"
|
||||
},
|
||||
"defaultSidePanelFieldList": {
|
||||
"detail": [
|
||||
"avatar"
|
||||
],
|
||||
"detailSmall": [
|
||||
"avatar"
|
||||
],
|
||||
"edit": [
|
||||
"avatar"
|
||||
],
|
||||
"editSmall": [
|
||||
"avatar"
|
||||
]
|
||||
},
|
||||
"sidePanels": {
|
||||
"detail": [
|
||||
{
|
||||
"name":"activities",
|
||||
"label":"Activities",
|
||||
"view":"crm:views/record/panels/activities",
|
||||
"aclScope": "Activities"
|
||||
},
|
||||
{
|
||||
"name":"history",
|
||||
"label":"History",
|
||||
"view":"crm:views/record/panels/history",
|
||||
"aclScope": "Activities"
|
||||
},
|
||||
{
|
||||
"name":"tasks",
|
||||
"label":"Tasks",
|
||||
"view":"crm:views/record/panels/tasks",
|
||||
"aclScope": "Task"
|
||||
}
|
||||
],
|
||||
"detailSmall": [
|
||||
{
|
||||
"name":"activities",
|
||||
"label":"Activities",
|
||||
"view":"crm:views/record/panels/activities",
|
||||
"aclScope": "Activities"
|
||||
},
|
||||
{
|
||||
"name":"history",
|
||||
"label":"History",
|
||||
"view":"crm:views/record/panels/history",
|
||||
"aclScope": "Activities"
|
||||
},
|
||||
{
|
||||
"name":"tasks",
|
||||
"label":"Tasks",
|
||||
"view":"crm:views/record/panels/tasks",
|
||||
"aclScope": "Task"
|
||||
}
|
||||
]
|
||||
},
|
||||
"filterList": [
|
||||
"active",
|
||||
"activePortal"
|
||||
|
||||
@@ -9,7 +9,12 @@
|
||||
"status": {
|
||||
"type": "enum",
|
||||
"options": ["In Process", "Complete", "Failed"],
|
||||
"readOnly": true
|
||||
"readOnly": true,
|
||||
"view": "views/fields/enum-styled",
|
||||
"style": {
|
||||
"Complete": "success",
|
||||
"Failed": "danger"
|
||||
}
|
||||
},
|
||||
"file": {
|
||||
"type": "file",
|
||||
|
||||
@@ -61,7 +61,8 @@
|
||||
},
|
||||
"collection": {
|
||||
"sortBy": "createdAt",
|
||||
"asc": false
|
||||
"asc": false,
|
||||
"textFilterFields": ["name", "method", "serviceName"]
|
||||
},
|
||||
"indexes": {
|
||||
"executeTime": {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"fields": {
|
||||
"post": {
|
||||
"type": "text"
|
||||
"type": "text",
|
||||
"rows": 8
|
||||
},
|
||||
"data": {
|
||||
"type": "jsonObject",
|
||||
@@ -58,9 +59,6 @@
|
||||
"isInternal": {
|
||||
"type": "bool"
|
||||
},
|
||||
"isToSelf": {
|
||||
"type": "bool"
|
||||
},
|
||||
"createdAt": {
|
||||
"type": "datetime",
|
||||
"readOnly": true
|
||||
|
||||
@@ -6,16 +6,16 @@
|
||||
},
|
||||
"recordsPerPage": {
|
||||
"type": "int",
|
||||
"minValue": 1,
|
||||
"maxValue": 1000,
|
||||
"min": 1,
|
||||
"max": 200,
|
||||
"default": 20,
|
||||
"required": true,
|
||||
"tooltip": true
|
||||
},
|
||||
"recordsPerPageSmall": {
|
||||
"type": "int",
|
||||
"minValue": 1,
|
||||
"maxValue": 100,
|
||||
"min": 1,
|
||||
"max": 100,
|
||||
"default": 10,
|
||||
"required": true,
|
||||
"tooltip": true
|
||||
@@ -306,7 +306,8 @@
|
||||
},
|
||||
"b2cMode": {
|
||||
"type": "bool",
|
||||
"default": false
|
||||
"default": false,
|
||||
"tooltip": true
|
||||
},
|
||||
"avatarsDisabled": {
|
||||
"type": "bool",
|
||||
@@ -402,7 +403,7 @@
|
||||
},
|
||||
"historyEntityList": {
|
||||
"type": "multiEnum",
|
||||
"view": "views/settings/fields/activities-entity-list"
|
||||
"view": "views/settings/fields/history-entity-list"
|
||||
},
|
||||
"googleMapsApiKey": {
|
||||
"type": "varchar"
|
||||
|
||||
@@ -253,6 +253,11 @@
|
||||
"entity": "Account",
|
||||
"foreign": "portalUsers",
|
||||
"relationName": "AccountPortalUser"
|
||||
},
|
||||
"tasks": {
|
||||
"type": "hasMany",
|
||||
"entity": "Task",
|
||||
"foreign": "assignedUser"
|
||||
}
|
||||
},
|
||||
"collection": {
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<p>{{assignerUserName}} has assigned {{entityTypeLowerFirst}} to you.</p>
|
||||
<p><strong>{{name}}</strong></p>
|
||||
<p><a href="{{recordUrl}}">View record</a></p>
|
||||
<p><a href="{{recordUrl}}">View</a></p>
|
||||
@@ -0,0 +1,4 @@
|
||||
<p>Email recieved from {{fromName}}, related to {{entityTypeLowerFirst}} '{{parentName}}'.</p>
|
||||
<p>{{subject}}</p>
|
||||
<p>{{{post}}}</p>
|
||||
<p><a href="{{url}}">View</a></p>
|
||||
@@ -0,0 +1 @@
|
||||
Email recieved: [{{{entityType}}}] {{{name}}}
|
||||
@@ -52,7 +52,7 @@ class EmailNotification extends \Espo\Core\Services\Base
|
||||
]);
|
||||
}
|
||||
|
||||
protected $noteNotificationTypeList = ['Post', 'Status'];
|
||||
protected $noteNotificationTypeList = ['Post', 'Status', 'EmailReceived'];
|
||||
|
||||
protected function getMailSender()
|
||||
{
|
||||
@@ -279,7 +279,6 @@ class EmailNotification extends \Espo\Core\Services\Base
|
||||
$note = $this->getEntityManager()->getEntity('Note', $notification->get('relatedId'));
|
||||
if (!$note) return;
|
||||
|
||||
$post = $note->get('post');
|
||||
$parentId = $note->get('parentId');
|
||||
$parentType = $note->get('parentType');
|
||||
|
||||
@@ -299,7 +298,7 @@ class EmailNotification extends \Espo\Core\Services\Base
|
||||
|
||||
$data['userName'] = $note->get('createdByName');
|
||||
|
||||
$data['post'] = $note->get('post');
|
||||
$data['post'] = nl2br($note->get('post'));
|
||||
|
||||
$subjectTpl = $this->getTemplateFileManager()->getTemplate('mention', 'subject');
|
||||
$bodyTpl = $this->getTemplateFileManager()->getTemplate('mention', 'body');
|
||||
@@ -361,7 +360,6 @@ class EmailNotification extends \Espo\Core\Services\Base
|
||||
|
||||
protected function processNotificationNotePost($note, $user)
|
||||
{
|
||||
$post = $note->get('post');
|
||||
$parentId = $note->get('parentId');
|
||||
$parentType = $note->get('parentType');
|
||||
|
||||
@@ -371,7 +369,7 @@ class EmailNotification extends \Espo\Core\Services\Base
|
||||
$data = array();
|
||||
|
||||
$data['userName'] = $note->get('createdByName');
|
||||
$data['post'] = $note->get('post');
|
||||
$data['post'] = nl2br($note->get('post'));
|
||||
|
||||
if ($parentId && $parentType) {
|
||||
$parent = $this->getEntityManager()->getEntity($parentType, $parentId);
|
||||
@@ -430,7 +428,6 @@ class EmailNotification extends \Espo\Core\Services\Base
|
||||
|
||||
protected function processNotificationNoteStatus($note, $user)
|
||||
{
|
||||
$post = $note->get('post');
|
||||
$parentId = $note->get('parentId');
|
||||
$parentType = $note->get('parentType');
|
||||
|
||||
@@ -491,4 +488,82 @@ class EmailNotification extends \Espo\Core\Services\Base
|
||||
$GLOBALS['log']->error('EmailNotification: [' . $e->getCode() . '] ' .$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
protected function processNotificationNoteEmailReceived($note, $user)
|
||||
{
|
||||
$parentId = $note->get('parentId');
|
||||
$parentType = $note->get('parentType');
|
||||
|
||||
$emailAddress = $user->get('emailAddress');
|
||||
if (!$emailAddress) return;
|
||||
|
||||
$noteData = $note->get('data');
|
||||
|
||||
if (!($noteData instanceof \StdClass)) return;
|
||||
|
||||
if (!isset($noteData->emailId)) return;
|
||||
$email = $this->getEntityManager()->getEntity('Email', $noteData->emailId);
|
||||
if (!$email) return;
|
||||
if ($email->hasLinkMultipleId('users', $user->id)) return;
|
||||
|
||||
$data = array();
|
||||
|
||||
$data['fromName'] = '';
|
||||
if (isset($noteData->personEntityName)) {
|
||||
$data['fromName'] = $noteData->personEntityName;
|
||||
} else if (isset($noteData->fromString)) {
|
||||
$data['fromName'] = $noteData->fromString;
|
||||
}
|
||||
|
||||
$data['subject'] = '';
|
||||
if (isset($noteData->emailName)) {
|
||||
$data['subject'] = $noteData->emailName;
|
||||
}
|
||||
|
||||
$data['post'] = nl2br($note->get('post'));
|
||||
|
||||
if (!$parentId || !$parentType) return;
|
||||
|
||||
$parent = $this->getEntityManager()->getEntity($parentType, $parentId);
|
||||
if (!$parent) return;
|
||||
|
||||
$data['url'] = $this->getConfig()->getSiteUrl() . '/#' . $parentType . '/view/' . $parentId;
|
||||
$data['parentName'] = $parent->get('name');
|
||||
$data['parentType'] = $parentType;
|
||||
$data['parentId'] = $parentId;
|
||||
|
||||
$data['name'] = $data['parentName'];
|
||||
|
||||
$data['entityType'] = $this->getLanguage()->translate($data['parentType'], 'scopeNames');
|
||||
$data['entityTypeLowerFirst'] = lcfirst($data['entityType']);
|
||||
|
||||
$subjectTpl = $this->getTemplateFileManager()->getTemplate('noteEmailRecieved', 'subject', $parentType);
|
||||
$bodyTpl = $this->getTemplateFileManager()->getTemplate('noteEmailRecieved', 'body', $parentType);
|
||||
|
||||
$subjectTpl = str_replace(array("\n", "\r"), '', $subjectTpl);
|
||||
|
||||
$subject = $this->getHtmlizer()->render($note, $subjectTpl, 'note-email-recieved-email-subject-' . $parentType, $data, true);
|
||||
$body = $this->getHtmlizer()->render($note, $bodyTpl, 'note-email-recieved-email-body-' . $parentType, $data, true);
|
||||
|
||||
$email = $this->getEntityManager()->getEntity('Email');
|
||||
|
||||
$email->set(array(
|
||||
'subject' => $subject,
|
||||
'body' => $body,
|
||||
'isHtml' => true,
|
||||
'to' => $emailAddress,
|
||||
'isSystem' => true
|
||||
));
|
||||
|
||||
$email->set(array(
|
||||
'parentId' => $parentId,
|
||||
'parentType' => $parentType
|
||||
));
|
||||
|
||||
try {
|
||||
$this->getMailSender()->send($email);
|
||||
} catch (\Exception $e) {
|
||||
$GLOBALS['log']->error('EmailNotification: [' . $e->getCode() . '] ' .$e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -271,6 +271,7 @@ class Import extends \Espo\Services\Record
|
||||
public function runIdleImport($data)
|
||||
{
|
||||
$entityType = $data['entityType'];
|
||||
|
||||
$params = json_decode(json_encode($data['params']), true);
|
||||
|
||||
$importFieldList = $data['importFieldList'];
|
||||
@@ -452,7 +453,11 @@ class Import extends \Espo\Services\Record
|
||||
|
||||
|
||||
if (!empty($params['defaultValues'])) {
|
||||
$v = get_object_vars($params['defaultValues']);
|
||||
if (is_object($params['defaultValues'])) {
|
||||
$v = get_object_vars($params['defaultValues']);
|
||||
} else {
|
||||
$v = $params['defaultValues'];
|
||||
}
|
||||
$entity->set($v);
|
||||
}
|
||||
|
||||
|
||||
@@ -530,6 +530,13 @@ class Record extends \Espo\Core\Services\Base
|
||||
$this->filterInput($data);
|
||||
$this->handleInput($data);
|
||||
|
||||
unset($data['modifiedById']);
|
||||
unset($data['modifiedByName']);
|
||||
unset($data['modifiedAt']);
|
||||
unset($data['createdById']);
|
||||
unset($data['createdByName']);
|
||||
unset($data['createdAt']);
|
||||
|
||||
$entity->set($data);
|
||||
|
||||
$this->beforeCreate($entity, $data);
|
||||
@@ -565,6 +572,13 @@ class Record extends \Espo\Core\Services\Base
|
||||
$this->filterInput($data);
|
||||
$this->handleInput($data);
|
||||
|
||||
unset($data['modifiedById']);
|
||||
unset($data['modifiedByName']);
|
||||
unset($data['modifiedAt']);
|
||||
unset($data['createdById']);
|
||||
unset($data['createdByName']);
|
||||
unset($data['createdAt']);
|
||||
|
||||
if ($this->getEntityBeforeUpdate) {
|
||||
$entity = $this->getEntity($id);
|
||||
} else {
|
||||
@@ -1168,7 +1182,8 @@ class Record extends \Espo\Core\Services\Base
|
||||
if (in_array($attribute, $attributeListToSkip)) {
|
||||
continue;
|
||||
}
|
||||
if (empty($entity->getAttributeParam($attribute, 'notStorable'))) {
|
||||
$isNotStorable = $entity->getAttributeParam($attribute, 'notStorable');
|
||||
if (!$isNotStorable) {
|
||||
$attributeList[] = $attribute;
|
||||
} else {
|
||||
if (in_array($entity->getAttributeParam($attribute, 'type'), ['email', 'phone'])) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{{#if isOverdue}}
|
||||
<span class="text-danger">
|
||||
{{/if}}
|
||||
{{value}}
|
||||
{{dateValue}}
|
||||
{{#if isOverdue}}
|
||||
</span>
|
||||
{{/if}}
|
||||
|
||||
@@ -100,7 +100,7 @@ Espo.define('crm:views/calendar/modals/edit', 'views/modals/edit', function (Dep
|
||||
if (!this.options.id && !this.options.scope) {
|
||||
var scopeList = [];
|
||||
this.scopeList.forEach(function (scope) {
|
||||
if (this.getAcl().check(scope, 'edit')) {
|
||||
if (this.getAcl().check(scope, 'create')) {
|
||||
if (~this.enabledScopeList.indexOf(scope)) {
|
||||
scopeList.push(scope);
|
||||
}
|
||||
|
||||
@@ -26,26 +26,28 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
Espo.define('crm:views/call/detail', 'views/detail', function (Dep) {
|
||||
Espo.define('crm:views/call/detail', ['views/detail', 'crm:views/meeting/detail'], function (Dep, MeetingDetail) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
setup: function () {
|
||||
Dep.prototype.setup.call(this);
|
||||
if (['Held', 'Not Held'].indexOf(this.model.get('status')) == -1) {
|
||||
if (this.getAcl().checkModel(this.model, 'edit') && this.getAcl().checkScope('Email', 'create')) {
|
||||
this.menu.buttons.push({
|
||||
'label': 'Send Invitations',
|
||||
'action': 'sendInvitations',
|
||||
'acl': 'edit',
|
||||
});
|
||||
|
||||
MeetingDetail.prototype.controlSendInvitationsButton.call(this);
|
||||
this.listenTo(this.model, 'change', function () {
|
||||
if (
|
||||
this.model.hasChanged('status')
|
||||
||
|
||||
this.model.hasChanged('teamsIds')
|
||||
) {
|
||||
MeetingDetail.prototype.controlSendInvitationsButton.call(this);
|
||||
}
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
actionSendInvitations: function () {
|
||||
if (confirm(this.translate('confirmation', 'messages'))) {
|
||||
this.$el.find('[data-action="sendInvitations"]').addClass('disabled');
|
||||
this.disableMenuItem('sendInvitations');
|
||||
this.notify('Sending...');
|
||||
$.ajax({
|
||||
url: 'Call/action/sendInvitations',
|
||||
@@ -53,12 +55,16 @@
|
||||
data: JSON.stringify({
|
||||
id: this.model.id
|
||||
}),
|
||||
success: function () {
|
||||
this.notify('Sent', 'success');
|
||||
this.$el.find('[data-action="sendInvitations"]').removeClass('disabled');
|
||||
success: function (result) {
|
||||
if (result) {
|
||||
this.notify('Sent', 'success');
|
||||
} else {
|
||||
Espo.Ui.warning(this.translate('nothingHasBeenSent', 'messages', 'Meeting'));
|
||||
}
|
||||
this.enableMenuItem('sendInvitations');
|
||||
}.bind(this),
|
||||
error: function () {
|
||||
this.$el.find('[data-action="sendInvitations"]').removeClass('disabled');
|
||||
this.enableMenuItem('sendInvitations');
|
||||
}.bind(this),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2015 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/.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
Espo.define('crm:views/contact/record/detail-small', ['views/record/detail-small', 'crm:views/contact/record/detail'], function (Dep, Detail) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
setup: function () {
|
||||
Dep.prototype.setup.call(this);
|
||||
|
||||
this.controlPortalUserVisibility();
|
||||
this.listenTo(this.model, 'change:portalUserId', this.controlPortalUserVisibility, this);
|
||||
},
|
||||
|
||||
controlPortalUserVisibility: function () {
|
||||
Detail.prototype.controlPortalUserVisibility.call(this);
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,49 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2015 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/.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
Espo.define('crm:views/contact/record/detail', 'views/record/detail', function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
setup: function () {
|
||||
Dep.prototype.setup.call(this);
|
||||
|
||||
this.controlPortalUserVisibility();
|
||||
this.listenTo(this.model, 'change:portalUserId', this.controlPortalUserVisibility, this);
|
||||
},
|
||||
|
||||
controlPortalUserVisibility: function () {
|
||||
if (this.model.get('portalUserId')) {
|
||||
this.showField('portalUser');
|
||||
} else {
|
||||
this.hideField('portalUser');
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
@@ -32,20 +32,55 @@ Espo.define('crm:views/meeting/detail', 'views/detail', function (Dep) {
|
||||
|
||||
setup: function () {
|
||||
Dep.prototype.setup.call(this);
|
||||
if (['Held', 'Not Held'].indexOf(this.model.get('status')) == -1) {
|
||||
if (this.getAcl().checkModel(this.model, 'edit') && this.getAcl().checkScope('Email', 'create')) {
|
||||
this.menu.buttons.push({
|
||||
'label': 'Send Invitations',
|
||||
'action': 'sendInvitations',
|
||||
'acl': 'edit',
|
||||
});
|
||||
this.controlSendInvitationsButton();
|
||||
this.listenTo(this.model, 'change', function () {
|
||||
if (
|
||||
this.model.hasChanged('status')
|
||||
||
|
||||
this.model.hasChanged('teamsIds')
|
||||
) {
|
||||
this.controlSendInvitationsButton();
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
controlSendInvitationsButton: function () {
|
||||
var show = true;;
|
||||
|
||||
if (
|
||||
~['Held', 'Not Held'].indexOf(this.model.get('status'))
|
||||
) {
|
||||
show = false;
|
||||
}
|
||||
|
||||
if (show && (!this.getAcl().checkModel(this.model, 'edit') || !this.getAcl().checkScope('Email', 'create'))) {
|
||||
show = false;
|
||||
}
|
||||
|
||||
if (show) {
|
||||
var userIdList = this.model.getLinkMultipleIdList('users');
|
||||
var contactIdList = this.model.getLinkMultipleIdList('contacts');
|
||||
var leadIdList = this.model.getLinkMultipleIdList('leads');
|
||||
|
||||
if (!contactIdList.length && !leadIdList.length && !userIdList.length) {
|
||||
show = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (show) {
|
||||
this.addMenuItem('buttons', {
|
||||
label: 'Send Invitations',
|
||||
action: 'sendInvitations',
|
||||
acl: 'edit',
|
||||
});
|
||||
} else {
|
||||
this.removeMenuItem('sendInvitations');
|
||||
}
|
||||
},
|
||||
|
||||
actionSendInvitations: function () {
|
||||
if (confirm(this.translate('confirmation', 'messages'))) {
|
||||
this.$el.find('button[data-action="sendInvitations"]').addClass('disabled');
|
||||
this.disableMenuItem('sendInvitations');
|
||||
this.notify('Sending...');
|
||||
$.ajax({
|
||||
url: 'Meeting/action/sendInvitations',
|
||||
@@ -53,12 +88,17 @@ Espo.define('crm:views/meeting/detail', 'views/detail', function (Dep) {
|
||||
data: JSON.stringify({
|
||||
id: this.model.id
|
||||
}),
|
||||
success: function () {
|
||||
this.notify('Sent', 'success');
|
||||
this.$el.find('[data-action="sendInvitations"]').removeClass('disabled');
|
||||
success: function (result) {
|
||||
if (result) {
|
||||
this.notify('Sent', 'success');
|
||||
} else {
|
||||
Espo.Ui.warning(this.translate('nothingHasBeenSent', 'messages', 'Meeting'));
|
||||
}
|
||||
|
||||
this.enableMenuItem('sendInvitations');
|
||||
}.bind(this),
|
||||
error: function () {
|
||||
this.$el.find('[data-action="sendInvitations"]').removeClass('disabled');
|
||||
this.enableMenuItem('sendInvitations');
|
||||
}.bind(this),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<% _.each(layout, function (panel, columnNumber) { %>
|
||||
<div class="panel panel-default<% if (panel.name) { %>{{#if hiddenPanels.<%= panel.name %>}} hidden{{/if}}<% } %>"<% if (panel.name) print(' data-name="'+panel.name+'"') %>>
|
||||
<div class="panel panel-<%= panel.style %><% if (panel.name) { %>{{#if hiddenPanels.<%= panel.name %>}} hidden{{/if}}<% } %>"<% if (panel.name) print(' data-name="'+panel.name+'"') %>>
|
||||
{{#if "<%= panel.label %>"}}
|
||||
<div class="panel-heading"><h4 class="panel-title"><%= "{{translate \"" + panel.label + "\" scope=\""+model.name+"\"}}" %></h4></div>
|
||||
{{/if}}
|
||||
|
||||
@@ -11,11 +11,11 @@
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
|
||||
#layout ul > li {
|
||||
background-color: #FFF;
|
||||
}
|
||||
|
||||
|
||||
#layout ul.panels > li {
|
||||
padding: 5px;
|
||||
margin: 5px;
|
||||
@@ -26,13 +26,13 @@
|
||||
{{/ifEqual}}
|
||||
min-height: 80px;
|
||||
border: 1px solid #CCC;
|
||||
list-style: none;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
|
||||
#layout ul.rows {
|
||||
min-height: 80px;
|
||||
}
|
||||
|
||||
|
||||
#layout ul.rows > li {
|
||||
list-style: none;
|
||||
border: 1px solid #CCC;
|
||||
@@ -40,111 +40,111 @@
|
||||
padding: 5px;
|
||||
height: 72px;
|
||||
}
|
||||
|
||||
|
||||
#layout ul.cells {
|
||||
min-height: 30px;
|
||||
margin-top: 12px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
|
||||
#layout ul.panels ul.cells > li {
|
||||
{{#ifEqual columnCount 1}}
|
||||
width: 92%;
|
||||
{{else}}
|
||||
width: 46%;
|
||||
{{/ifEqual}}
|
||||
{{/ifEqual}}
|
||||
float: left;
|
||||
}
|
||||
|
||||
|
||||
#layout ul.panels ul.cells > li[data-full-width="true"] {
|
||||
width: 94%;
|
||||
}
|
||||
|
||||
|
||||
#layout ul.cells > li {
|
||||
list-style: none;
|
||||
border: 1px solid #CCC;
|
||||
margin: 5px;
|
||||
padding: 5px;
|
||||
height: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
|
||||
#layout ul.rows > li > div {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#layout ul.cells > li a {
|
||||
float: right;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
|
||||
#layout ul.disabled {
|
||||
min-height: 200px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
#layout ul.disabled > li a {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
#layout header {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
#layout ul.panels > li label {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
|
||||
#layout ul.panels > li header a {
|
||||
font-weight: normal;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
|
||||
#layout ul.panels > li > div {
|
||||
width: auto;
|
||||
text-align: left;
|
||||
margin-left: 5px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
|
||||
ul.cells li.cell a.remove-field {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
ul.cells li.cell:hover a.remove-field {
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
||||
ul.panels > li a.remove-panel {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
ul.panels > li:hover a.remove-panel {
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
||||
ul.rows > li a.remove-row {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
ul.rows > li:hover a.remove-row {
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
||||
ul.panels > li a.edit-panel-label {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
ul.panels > li:hover a.edit-panel-label {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
|
||||
<div id="layout" class="row">
|
||||
<div class="col-md-8">
|
||||
<div class="well">
|
||||
<header>Layout</header>
|
||||
<a href="javascript:;" data-action="addPanel">{{translate 'Add Panel' scope='Admin'}}</a>
|
||||
<header>Layout</header>
|
||||
<a href="javascript:;" data-action="addPanel">{{translate 'Add Panel' scope='Admin'}}</a>
|
||||
<ul class="panels"></ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="well">
|
||||
@@ -152,21 +152,21 @@
|
||||
<ul class="disabled cells clearfix">
|
||||
{{#each disabledFields}}
|
||||
<li class="cell" data-name="{{./this}}">{{translate this scope=../scope category='fields'}}
|
||||
<a href="javascript:" data-action="removeField" class="remove-field"><i class="glyphicon glyphicon-remove"></i></a>
|
||||
<a href="javascript:" data-action="removeField" class="remove-field"><i class="glyphicon glyphicon-remove"></i></a>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="layout-panel-tpl" style="display: none;">
|
||||
<li>
|
||||
<header>
|
||||
<header data-style="<%= style %>">
|
||||
<label><%= label %></label>
|
||||
<a href="javascript:" data-action="edit-panel-label" class="edit-panel-label"><i class="glyphicon glyphicon-pencil"></i></a>
|
||||
<a href="javascript:" style="float: right;" data-action="removePanel" class="remove-panel"><i class="glyphicon glyphicon-remove"></i></a>
|
||||
</header>
|
||||
</header>
|
||||
<ul class="rows">
|
||||
<%
|
||||
for (var i in rows) {
|
||||
@@ -184,23 +184,23 @@
|
||||
if (cell !== false) {
|
||||
%>
|
||||
<li class="cell" data-name="<%= cell.name %>" data-full-width="<%= cell.fullWidth || '' %>"><%= cell.label %>
|
||||
<a href="javascript:" data-action="removeField" class="remove-field"><i class="glyphicon glyphicon-remove"></i></a>
|
||||
<a href="javascript:" data-action="removeField" class="remove-field"><i class="glyphicon glyphicon-remove"></i></a>
|
||||
</li>
|
||||
<%
|
||||
<%
|
||||
} else {
|
||||
%>
|
||||
<li class="empty cell">
|
||||
<a href="javascript:" data-action="minusCell" class="remove-field"><i class="glyphicon glyphicon-minus"></i></a>
|
||||
</li>
|
||||
<%
|
||||
<%
|
||||
}
|
||||
}
|
||||
%>
|
||||
%>
|
||||
</ul>
|
||||
</li>
|
||||
</li>
|
||||
<%
|
||||
}
|
||||
%>
|
||||
%>
|
||||
</ul>
|
||||
<div>
|
||||
<a href="javascript:" data-action="addRow"><i class="glyphicon glyphicon-plus"></i></a>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
|
||||
#layout ul li {
|
||||
list-style: none;
|
||||
border: 1px solid #CCC;
|
||||
@@ -20,45 +20,43 @@
|
||||
padding: 5px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
|
||||
#layout header {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
#layout ul > li .left {
|
||||
float: left;
|
||||
}
|
||||
|
||||
|
||||
#layout ul > li {
|
||||
background-color: #FFF;
|
||||
}
|
||||
|
||||
|
||||
#layout ul.enabled > li .right {
|
||||
float: right;
|
||||
}
|
||||
|
||||
|
||||
#layout ul.disabled > li .right {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#layout ul > li .width {
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
|
||||
#layout ul.disabled > li .width {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
#layout label {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
|
||||
.enabled li a.edit-field {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
.enabled li:hover a.edit-field {
|
||||
display: block;
|
||||
}
|
||||
@@ -70,7 +68,7 @@
|
||||
<header>{{translate 'Enabled' scope='Admin'}}</header>
|
||||
<ul class="enabled connected">
|
||||
{{#each layout}}
|
||||
<li draggable="true" {{#each ../dataAttributes}}data-{{toDom this}}="{{prop ../this this}}" {{/each}}>
|
||||
<li draggable="true" {{#each ../dataAttributeList}}data-{{toDom this}}="{{prop ../this this}}" {{/each}}>
|
||||
<div class="left">
|
||||
<label>{{label}}</label>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{{dateValue}}
|
||||
@@ -1,6 +1,6 @@
|
||||
<div class="input-group">
|
||||
<input class="main-element form-control" type="text" name="{{name}}" value="{{value}}" autocomplete="off">
|
||||
<span class="input-group-btn">
|
||||
<button type="button" class="btn btn-default date-picker-btn" tabindex="-1"><i class="glyphicon glyphicon-calendar"></i></button>
|
||||
<input class="main-element form-control" type="text" name="{{name}}" value="{{dateValue}}" autocomplete="off">
|
||||
<span class="input-group-btn">
|
||||
<button type="button" class="btn btn-default date-picker-btn" tabindex="-1"><i class="glyphicon glyphicon-calendar"></i></button>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{{dateValue}}
|
||||
@@ -0,0 +1 @@
|
||||
<span title="{{fullDateValue}}">{{dateValue}}</span>
|
||||
@@ -0,0 +1 @@
|
||||
<span title="{{fullDateValue}}">{{dateValue}}</span>
|
||||
@@ -1 +1,5 @@
|
||||
<span class="text-{{style}}">{{translateOption value scope=scope field=name}}</span>
|
||||
{{#if isNotEmpty}}
|
||||
<span class="text-{{style}}">{{translateOption value scope=scope field=name}}</span>
|
||||
{{else}}
|
||||
{{translate 'None'}}
|
||||
{{/if}}
|
||||
@@ -0,0 +1,3 @@
|
||||
{{#if isNotEmpty}}
|
||||
<span class="text-{{style}}">{{translateOption value scope=scope field=name}}</span>
|
||||
{{/if}}
|
||||
@@ -1 +1,5 @@
|
||||
{{translateOption value scope=scope field=name translatedOptions=translatedOptions}}
|
||||
{{#if isNotEmpty}}
|
||||
{{translateOption value scope=scope field=name translatedOptions=translatedOptions}}
|
||||
{{else}}
|
||||
{{translate 'None'}}
|
||||
{{/if}}
|
||||
@@ -0,0 +1,3 @@
|
||||
{{#if isNotEmpty}}
|
||||
{{translateOption value scope=scope field=name translatedOptions=translatedOptions}}
|
||||
{{/if}}
|
||||
@@ -1,3 +1 @@
|
||||
<span class="complext-text">
|
||||
{{complexText value}}
|
||||
</span>
|
||||
{{#if isNotEmpty}}<span class="complext-text">{{complexText value}}</span>{{else}}{{translate 'None'}}{{/if}}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{{#if idValue}}
|
||||
{{{avatar}}}
|
||||
<a href="#{{foreignScope}}/view/{{idValue}}">{{nameValue}}</a>
|
||||
{{/if}}
|
||||
@@ -0,0 +1 @@
|
||||
{{#if isNotEmpty}}{{value}}{{else}}{{translate 'None'}}{{/if}}
|
||||
@@ -1,14 +1,14 @@
|
||||
{{#each panelList}}
|
||||
<div class="panel panel-default panel-{{name}}{{#if hidden}} hidden{{/if}}{{#if sticked}} sticked{{/if}}" data-name="{{name}}" data-name="{{name}}">
|
||||
<div class="panel panel-{{#if style}}{{style}}{{else}}default{{/if}} panel-{{name}}{{#if hidden}} hidden{{/if}}{{#if sticked}} sticked{{/if}}" data-name="{{name}}" data-name="{{name}}">
|
||||
<div class="panel-heading">
|
||||
<div class="pull-right btn-group">
|
||||
{{#if buttonList}}
|
||||
{{#each buttonList}}
|
||||
<button type="button" class="btn btn-default btn-sm action{{#if hidden}} hidden{{/if}}" data-action="{{action}}" data-panel="{{../../name}}" {{#each data}} data-{{hyphen @key}}="{{./this}}"{{/each}} title="{{translate title scope=../../scope}}">{{#if html}}{{{html}}}{{else}}{{translate label scope=../../../../scope}}{{/if}}</button>
|
||||
<button type="button" class="btn btn-{{#if ../../style}}{{../../style}}{{else}}default{{/if}} btn-sm action{{#if hidden}} hidden{{/if}}" data-action="{{action}}" data-panel="{{../../name}}" {{#each data}} data-{{hyphen @key}}="{{./this}}"{{/each}} title="{{translate title scope=../../scope}}">{{#if html}}{{{html}}}{{else}}{{translate label scope=../../../../scope}}{{/if}}</button>
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
{{#if actionList}}
|
||||
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown">
|
||||
<button type="button" class="btn btn-{{#if ../style}}{{../style}}{{else}}default{{/if}} btn-sm dropdown-toggle" data-toggle="dropdown">
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
{{#each panelList}}
|
||||
<div class="panel panel-default panel-{{name}}{{#if hidden}} hidden{{/if}}{{#if sticked}} sticked{{/if}}" data-name="{{name}}" data-name="{{name}}">
|
||||
<div class="panel panel-{{#if style}}{{style}}{{else}}default{{/if}} panel-{{name}}{{#if hidden}} hidden{{/if}}{{#if sticked}} sticked{{/if}}" data-name="{{name}}" data-name="{{name}}">
|
||||
{{#if label}}
|
||||
<div class="panel-heading">
|
||||
<div class="pull-right btn-group">
|
||||
{{#if buttonList}}
|
||||
{{#each buttonList}}
|
||||
<button type="button" class="btn btn-default btn-sm action{{#if hidden}} hidden{{/if}}" data-action="{{action}}" data-panel="{{../../name}}" {{#each data}} data-{{hyphen @key}}="{{./this}}"{{/each}} title="{{translate title scope=../scope}}">{{#if html}}{{{html}}}{{else}}{{translate label scope=../../../../scope}}{{/if}}</button>
|
||||
<button type="button" class="btn btn-{{#if ../../style}}{{../../style}}{{else}}default{{/if}} btn-sm action{{#if hidden}} hidden{{/if}}" data-action="{{action}}" data-panel="{{../../name}}" {{#each data}} data-{{hyphen @key}}="{{./this}}"{{/each}} title="{{translate title scope=../scope}}">{{#if html}}{{{html}}}{{else}}{{translate label scope=../../../../scope}}{{/if}}</button>
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
{{#if actionList}}
|
||||
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown">
|
||||
<button type="button" class="btn btn-{{#if style}}{{style}}{{else}}default{{/if}} btn-sm dropdown-toggle" data-toggle="dropdown">
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
|
||||
+5
-1
@@ -61,7 +61,7 @@ Espo.define(
|
||||
|
||||
this.setupAjax();
|
||||
|
||||
this.settings = new Settings(null, {cache: this.cache});
|
||||
this.settings = new Settings(null);
|
||||
this.language = new Language(this.cache);
|
||||
this.metadata = new Metadata(this.cache);
|
||||
this.fieldManager = new FieldManager();
|
||||
@@ -470,8 +470,12 @@ Espo.define(
|
||||
var preferencesData = options.preferences || null;
|
||||
var aclData = options.acl || null;
|
||||
|
||||
var settingData = options.settings || {};
|
||||
|
||||
this.user.set(userData);
|
||||
this.preferences.set(preferencesData);
|
||||
|
||||
this.settings.set(settingData);
|
||||
this.acl.set(aclData);
|
||||
|
||||
if (!this.auth) {
|
||||
|
||||
+12
-11
@@ -67,7 +67,7 @@ Espo.define('cache', [], function () {
|
||||
|
||||
_checkType: function (type) {
|
||||
if (typeof type === 'undefined' && toString.call(type) != '[object String]') {
|
||||
throw new TypeError("Bad type \"" + type + "\" passed to Bull.Cacher().");
|
||||
throw new TypeError("Bad type \"" + type + "\" passed to Cache().");
|
||||
}
|
||||
},
|
||||
|
||||
@@ -77,25 +77,26 @@ Espo.define('cache', [], function () {
|
||||
var key = this._composeKey(type, name);
|
||||
var stored = localStorage.getItem(key);
|
||||
if (stored) {
|
||||
var str = stored;
|
||||
if (stored[0] == "{" || stored[0] == "[") {
|
||||
try {
|
||||
str = JSON.parse(stored);
|
||||
var result = stored;
|
||||
|
||||
if (stored.length > 9 && stored.substr(0, 9) === '__JSON__:') {
|
||||
var jsonString = stored.substr(9);
|
||||
try {
|
||||
result = JSON.parse(jsonString);
|
||||
} catch (error) {
|
||||
str = stored;
|
||||
result = stored;
|
||||
}
|
||||
stored = str;
|
||||
}
|
||||
return stored;
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
set: function (type, name, value) {
|
||||
this._checkType(type);
|
||||
var key = this._composeKey(type, name);
|
||||
if (value instanceof Object) {
|
||||
value = JSON.stringify(value);
|
||||
var key = this._composeKey(type, name);
|
||||
if (value instanceof Object || Array.isArray(value)) {
|
||||
value = '__JSON__:' + JSON.stringify(value);
|
||||
}
|
||||
localStorage.setItem(key, value);
|
||||
},
|
||||
|
||||
@@ -117,10 +117,10 @@ Espo.define('language', [], function () {
|
||||
}
|
||||
}
|
||||
|
||||
this.fetch();
|
||||
this.fetch(false, disableCache);
|
||||
},
|
||||
|
||||
fetch: function (sync) {
|
||||
fetch: function (sync, disableCache) {
|
||||
var self = this;
|
||||
$.ajax({
|
||||
url: this.url,
|
||||
@@ -129,7 +129,9 @@ Espo.define('language', [], function () {
|
||||
async: !(sync || false),
|
||||
success: function (data) {
|
||||
self.data = data;
|
||||
self.storeToCache();
|
||||
if (!disableCache) {
|
||||
self.storeToCache();
|
||||
}
|
||||
self.trigger('sync');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -31,6 +31,31 @@ Espo.define('models/settings', 'model-offline', function (Dep) {
|
||||
|
||||
name: 'Settings',
|
||||
|
||||
getByPath: function (arr) {
|
||||
if (!arr.length) return null;
|
||||
|
||||
var p;
|
||||
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
var item = arr[i];
|
||||
if (i == 0) {
|
||||
p = this.get(item);
|
||||
} else {
|
||||
if (item in p) {
|
||||
p = p[item];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (i === arr.length - 1) {
|
||||
return p;
|
||||
}
|
||||
if (p === null || typeof p !== 'object') {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user