Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| be6661454b | |||
| 889a19b9bd | |||
| ec242152e7 | |||
| e0ae3beef9 | |||
| 4c6dd88a2d | |||
| d13a1ffbc7 | |||
| 986be9f189 | |||
| 40f13f7a3d | |||
| 2de3c97f8d | |||
| 3b6fd0d363 | |||
| a7586e92a1 | |||
| 076644db85 | |||
| 7eb139f35d | |||
| 6f22686319 | |||
| 298307f613 | |||
| 664faa81ca | |||
| be2dd74c43 | |||
| d2ae211e53 | |||
| e522d8d709 | |||
| c5c191faa6 | |||
| 3ce4cd3bfc | |||
| e620a1195f | |||
| 880478689f | |||
| 0d5d1710bf | |||
| 0c7d795081 | |||
| 624bdb7192 | |||
| db769d9c3e | |||
| 67045b12ac | |||
| e67ab0fd4d | |||
| 99c64770dd | |||
| ed60efcad4 | |||
| 443af201ed | |||
| 7a61dd096e | |||
| 9404c1d165 | |||
| 2a76db6899 | |||
| 915283d288 | |||
| 483e6e9d5b | |||
| 046d94ceb8 | |||
| 062008374d | |||
| df2f857197 | |||
| 25c88259f8 | |||
| 2ddfa39966 | |||
| ebec204d3a |
@@ -73,12 +73,18 @@ class UserColumnsLoader implements Loader
|
||||
return;
|
||||
}
|
||||
|
||||
$entity->set([
|
||||
$values = [
|
||||
Email::USERS_COLUMN_IS_READ => $emailUser->get(Email::USERS_COLUMN_IS_READ),
|
||||
Email::USERS_COLUMN_IS_IMPORTANT => $emailUser->get(Email::USERS_COLUMN_IS_IMPORTANT),
|
||||
Email::USERS_COLUMN_IN_TRASH => $emailUser->get(Email::USERS_COLUMN_IN_TRASH),
|
||||
Email::USERS_COLUMN_IN_ARCHIVE => $emailUser->get(Email::USERS_COLUMN_IN_ARCHIVE),
|
||||
'isUsersSent' => $entity->getSentBy()?->getId() === $this->user->getId(),
|
||||
]);
|
||||
];
|
||||
|
||||
$entity->setMultiple($values);
|
||||
|
||||
foreach ($values as $key => $value) {
|
||||
$entity->setFetched($key, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,8 +31,10 @@ namespace Espo\Classes\RecordHooks\Email;
|
||||
|
||||
use Espo\Core\Mail\EmailSender;
|
||||
use Espo\Core\Name\Field;
|
||||
use Espo\Core\ORM\Type\FieldType;
|
||||
use Espo\Core\Record\Hook\SaveHook;
|
||||
use Espo\Core\Utils\FieldUtil;
|
||||
use Espo\Core\Utils\Metadata;
|
||||
use Espo\Core\Utils\SystemUser;
|
||||
use Espo\Entities\Email;
|
||||
use Espo\Entities\User;
|
||||
@@ -54,7 +56,8 @@ class BeforeUpdate implements SaveHook
|
||||
public function __construct(
|
||||
private User $user,
|
||||
private EntityManager $entityManager,
|
||||
private FieldUtil $fieldUtil
|
||||
private FieldUtil $fieldUtil,
|
||||
private Metadata $metadata,
|
||||
) {}
|
||||
|
||||
public function process(Entity $entity): void
|
||||
@@ -125,18 +128,24 @@ class BeforeUpdate implements SaveHook
|
||||
|
||||
private function clearEntityForUpdate(Email $email): void
|
||||
{
|
||||
$fieldDefsList = $this->entityManager
|
||||
$entityDefs = $this->entityManager
|
||||
->getDefs()
|
||||
->getEntity(Email::ENTITY_TYPE)
|
||||
->getFieldList();
|
||||
->getEntity(Email::ENTITY_TYPE);
|
||||
|
||||
foreach ($fieldDefsList as $fieldDefs) {
|
||||
foreach ($entityDefs->getFieldList() as $fieldDefs) {
|
||||
$field = $fieldDefs->getName();
|
||||
|
||||
if ($fieldDefs->getParam('isCustom')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
$fieldDefs->getType() === FieldType::LINK_MULTIPLE &&
|
||||
$this->metadata->get("entityDefs.Email.links.$field.isCustom")
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (in_array($field, $this->allowedForUpdateFieldList)) {
|
||||
continue;
|
||||
}
|
||||
@@ -144,7 +153,9 @@ class BeforeUpdate implements SaveHook
|
||||
$attributeList = $this->fieldUtil->getAttributeList(Email::ENTITY_TYPE, $field);
|
||||
|
||||
foreach ($attributeList as $attribute) {
|
||||
$email->clear($attribute);
|
||||
if ($email->isAttributeChanged($attribute) && $email->isAttributeWritten($attribute)) {
|
||||
$email->set($attribute, $email->getFetched($attribute));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,10 +248,8 @@ class ClientManager
|
||||
$params[$k] = $v;
|
||||
}
|
||||
|
||||
$client = new $className($oauth2Client, $params, $this);
|
||||
|
||||
if ($this->injectableFactory) {
|
||||
$this->injectableFactory->createWith($className, [
|
||||
$client = $this->injectableFactory->createWith($className, [
|
||||
'client' => $oauth2Client,
|
||||
'params' => $params,
|
||||
'manager' => $this,
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Formula\Functions\ExtGroup\SecretGroup;
|
||||
|
||||
use Espo\Core\Formula\EvaluatedArgumentList;
|
||||
use Espo\Core\Formula\Exceptions\BadArgumentType;
|
||||
use Espo\Core\Formula\Exceptions\Error;
|
||||
use Espo\Core\Formula\Exceptions\TooFewArguments;
|
||||
use Espo\Core\Formula\Func;
|
||||
use Espo\Tools\AppSecret\SecretProvider;
|
||||
|
||||
/**
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
class GetType implements Func
|
||||
{
|
||||
public function __construct(private SecretProvider $secretProvider)
|
||||
{}
|
||||
|
||||
public function process(EvaluatedArgumentList $arguments): string
|
||||
{
|
||||
if (count($arguments) < 1) {
|
||||
throw TooFewArguments::create(1);
|
||||
}
|
||||
|
||||
$string = $arguments[0];
|
||||
|
||||
if (!is_string($string)) {
|
||||
throw BadArgumentType::create(1, 'string');
|
||||
}
|
||||
|
||||
$secret = $this->secretProvider->get($string);
|
||||
|
||||
if ($secret === null) {
|
||||
throw new Error("No secret '$string'.");
|
||||
}
|
||||
|
||||
return $secret;
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,7 @@ use Espo\Core\Formula\Exceptions\Error;
|
||||
use Espo\Core\Formula\Functions\BaseFunction;
|
||||
use Espo\Core\Formula\Functions\RecordGroup\Util\FindQueryUtil;
|
||||
use Espo\Core\Di;
|
||||
use Espo\Core\Select\Primary\Filters\All;
|
||||
use Espo\Core\Select\SelectBuilderFactory;
|
||||
|
||||
/**
|
||||
@@ -68,6 +69,7 @@ class CountType extends BaseFunction implements
|
||||
$builder = $this->injectableFactory->create(SelectBuilderFactory::class)
|
||||
->create()
|
||||
->forUser($this->user)
|
||||
->withPrimaryFilter(All::NAME)
|
||||
->from($entityType);
|
||||
|
||||
(new FindQueryUtil())->applyFilter($builder, $filter, 2);
|
||||
|
||||
@@ -36,6 +36,7 @@ use Espo\Core\Formula\Exceptions\Error;
|
||||
use Espo\Core\Formula\Functions\BaseFunction;
|
||||
use Espo\Core\Di;
|
||||
use Espo\Core\Formula\Functions\RecordGroup\Util\FindQueryUtil;
|
||||
use Espo\Core\Select\Primary\Filters\All;
|
||||
use Espo\Core\Select\SelectBuilderFactory;
|
||||
|
||||
/**
|
||||
@@ -68,6 +69,7 @@ class ExistsType extends BaseFunction implements
|
||||
$builder = $this->injectableFactory->create(SelectBuilderFactory::class)
|
||||
->create()
|
||||
->forUser($this->user)
|
||||
->withPrimaryFilter(All::NAME)
|
||||
->from($entityType);
|
||||
|
||||
(new FindQueryUtil())->applyFilter($builder, $filter, 2);
|
||||
|
||||
@@ -38,6 +38,7 @@ use Espo\Core\Formula\Exceptions\Error as FormulaError;
|
||||
use Espo\Core\Formula\Exceptions\TooFewArguments;
|
||||
use Espo\Core\Formula\Func;
|
||||
use Espo\Core\Formula\Functions\RecordGroup\Util\FindQueryUtil;
|
||||
use Espo\Core\Select\Primary\Filters\All;
|
||||
use Espo\Core\Select\SelectBuilderFactory;
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\ORM\EntityManager;
|
||||
@@ -92,6 +93,7 @@ class FindManyType implements Func
|
||||
|
||||
$builder = $this->selectBuilderFactory
|
||||
->create()
|
||||
->withPrimaryFilter(All::NAME)
|
||||
->from($entityType);
|
||||
|
||||
$whereClause = [];
|
||||
|
||||
@@ -36,6 +36,7 @@ use Espo\Core\Formula\Exceptions\Error as FormulaError;
|
||||
use Espo\Core\Formula\Functions\BaseFunction;
|
||||
use Espo\Core\Di;
|
||||
use Espo\Core\Formula\Functions\RecordGroup\Util\FindQueryUtil;
|
||||
use Espo\Core\Select\Primary\Filters\All;
|
||||
use Espo\Core\Select\SelectBuilderFactory;
|
||||
use Espo\ORM\Name\Attribute;
|
||||
use Espo\ORM\Query\Part\Order;
|
||||
@@ -65,6 +66,7 @@ class FindOneType extends BaseFunction implements
|
||||
$builder = $this->injectableFactory->create(SelectBuilderFactory::class)
|
||||
->create()
|
||||
->forUser($this->user)
|
||||
->withPrimaryFilter(All::NAME)
|
||||
->from($entityType);
|
||||
|
||||
$whereClause = [];
|
||||
|
||||
@@ -41,6 +41,7 @@ use Espo\Core\Formula\ArgumentList;
|
||||
use Espo\Core\Formula\Functions\BaseFunction;
|
||||
use Espo\Core\Di;
|
||||
use Espo\Core\Select\Helpers\RandomStringGenerator;
|
||||
use Espo\Core\Select\Primary\Filters\All;
|
||||
use Espo\Core\Select\SelectBuilderFactory;
|
||||
use Espo\ORM\Defs\Params\RelationParam;
|
||||
use Espo\ORM\Name\Attribute;
|
||||
@@ -165,6 +166,7 @@ class FindRelatedManyType extends BaseFunction implements
|
||||
$builder = $this->injectableFactory->create(SelectBuilderFactory::class)
|
||||
->create()
|
||||
->forUser($this->user)
|
||||
->withPrimaryFilter(All::NAME)
|
||||
->from($foreignEntityType);
|
||||
|
||||
$whereClause = [];
|
||||
|
||||
@@ -32,6 +32,7 @@ namespace Espo\Core\Formula\Functions\RecordGroup;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\ORM\Entity as CoreEntity;
|
||||
use Espo\Core\Select\Primary\Filters\All;
|
||||
use Espo\Core\Select\SelectBuilderFactory;
|
||||
use Espo\ORM\Defs\Params\RelationParam;
|
||||
use Espo\ORM\Name\Attribute;
|
||||
@@ -151,6 +152,7 @@ class FindRelatedOneType extends BaseFunction implements
|
||||
$builder = $this->injectableFactory->create(SelectBuilderFactory::class)
|
||||
->create()
|
||||
->forUser($this->user)
|
||||
->withPrimaryFilter(All::NAME)
|
||||
->from($foreignEntityType);
|
||||
|
||||
$whereClause = [];
|
||||
|
||||
@@ -95,7 +95,7 @@ class Entity extends BaseEntity
|
||||
throw new LogicException("No entity-manager.");
|
||||
}
|
||||
|
||||
$toSetFetched = !$this->isNew() && !$this->hasFetched($idAttribute);
|
||||
$toSetFetched = !$this->isNew() && !$this->isAttributeChanged($idAttribute);
|
||||
|
||||
if (!$parentId || !$parentType) {
|
||||
/** @noinspection PhpRedundantOptionalArgumentInspection */
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Utils\Database\Dbal\Platforms\Keywords;
|
||||
|
||||
use Doctrine\DBAL\Platforms\Keywords\MariaDBKeywords;
|
||||
|
||||
/**
|
||||
* 'LEAD' happened to be a reserved words on some environments.
|
||||
*/
|
||||
final class MariaDb102Keywords extends MariaDBKeywords
|
||||
{
|
||||
/** @deprecated */
|
||||
public function getName(): string
|
||||
{
|
||||
return 'MariaDb102';
|
||||
}
|
||||
|
||||
protected function getKeywords(): array
|
||||
{
|
||||
return [
|
||||
...parent::getKeywords(),
|
||||
'LEAD',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -129,6 +129,12 @@ class LogicDefsBc implements AdditionalBuilder
|
||||
$item = $subDefs->$subKey;
|
||||
|
||||
$logicDefs->$key ??= (object) [];
|
||||
|
||||
// Fix if corrupted.
|
||||
if (is_array($logicDefs->$key)) {
|
||||
$logicDefs->$key = (object) [];
|
||||
}
|
||||
|
||||
$logicDefs->$key->$name ??= (object) [];
|
||||
|
||||
$logicDefs->$key->$name->$subKey = $item !== null ?
|
||||
|
||||
@@ -126,6 +126,24 @@ class Email extends Entity
|
||||
return parent::has($attribute);
|
||||
}
|
||||
|
||||
public function getFetched(string $attribute): mixed
|
||||
{
|
||||
if ($attribute === 'subject') {
|
||||
return $this->getFetched(Field::NAME);
|
||||
}
|
||||
|
||||
return parent::getFetched($attribute);
|
||||
}
|
||||
|
||||
public function isAttributeChanged(string $name): bool
|
||||
{
|
||||
if ($name === 'subject') {
|
||||
$name = Field::NAME;
|
||||
}
|
||||
|
||||
return parent::isAttributeChanged($name);
|
||||
}
|
||||
|
||||
/** @noinspection PhpUnused */
|
||||
protected function _setSubject(?string $value): void
|
||||
{
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
[
|
||||
{
|
||||
"label":"",
|
||||
"rows":[
|
||||
[{"name":"name", "fullWidth": true}],
|
||||
[{"name":"name"}],
|
||||
[{"name":"status"}, {"name":"direction"}],
|
||||
[{"name":"dateStart", "fullWidth": true}],
|
||||
[{"name":"duration", "fullWidth": true}],
|
||||
[{"name":"dateEnd", "fullWidth": true}],
|
||||
[{"name":"parent", "fullWidth": true}],
|
||||
[{"name":"reminders", "fullWidth": true}],
|
||||
[{"name":"description", "fullWidth": true}]
|
||||
[{"name":"dateStart"}],
|
||||
[{"name":"duration"}, false],
|
||||
[{"name":"dateEnd"}],
|
||||
[{"name":"parent"}],
|
||||
[{"name":"reminders"}],
|
||||
[{"name":"description"}]
|
||||
]
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
[
|
||||
{
|
||||
"label":"",
|
||||
"rows":[
|
||||
[{"name":"name", "fullWidth": true}],
|
||||
[{"name":"status"}, {"name":"priority"}],
|
||||
[{"name":"type"}, {"name":"number"}],
|
||||
[{"name":"account", "fullWidth": true}],
|
||||
[{"name":"contacts", "fullWidth": true}],
|
||||
[{"name":"description", "fullWidth": true}],
|
||||
[{"name":"attachments", "fullWidth": true}]
|
||||
[{"name": "name"}],
|
||||
[{"name": "status"}, {"name": "priority"}],
|
||||
[{"name": "type"}, {"name": "number"}],
|
||||
[{"name": "account"}, {"name": "contacts"}],
|
||||
[{"name": "description"}],
|
||||
[{"name": "attachments"}]
|
||||
]
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
[
|
||||
{
|
||||
"label":"",
|
||||
"rows":[
|
||||
[{"name":"name", "fullWidth": true}],
|
||||
[{"name":"status", "fullWidth": true}],
|
||||
[{"name":"dateStart", "fullWidth": true}],
|
||||
[{"name":"duration", "fullWidth": true}],
|
||||
[{"name":"dateEnd", "fullWidth": true}],
|
||||
[{"name":"parent", "fullWidth": true}],
|
||||
[{"name":"reminders", "fullWidth": true}],
|
||||
[{"name":"description", "fullWidth": true}]
|
||||
[{"name":"name"}],
|
||||
[{"name":"status"}, false],
|
||||
[{"name":"dateStart"}],
|
||||
[{"name":"duration"}, false],
|
||||
[{"name":"dateEnd"}],
|
||||
[{"name":"parent"}],
|
||||
[{"name":"reminders"}],
|
||||
[{"name":"description"}]
|
||||
]
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
@@ -84,25 +84,18 @@ class ConvertService
|
||||
{
|
||||
$lead = $this->getLead($id);
|
||||
|
||||
$duplicateList = [];
|
||||
$skipSave = false;
|
||||
|
||||
$duplicateCheck = !$params->skipDuplicateCheck();
|
||||
if (!$params->skipDuplicateCheck()) {
|
||||
$this->processDuplicateCheck($records);
|
||||
}
|
||||
|
||||
$account = $this->processAccount(
|
||||
lead: $lead,
|
||||
records: $records,
|
||||
duplicateCheck: $duplicateCheck,
|
||||
duplicateList: $duplicateList,
|
||||
skipSave: $skipSave,
|
||||
);
|
||||
|
||||
$contact = $this->processContact(
|
||||
lead: $lead,
|
||||
records: $records,
|
||||
duplicateCheck: $duplicateCheck,
|
||||
duplicateList: $duplicateList,
|
||||
skipSave: $skipSave,
|
||||
account: $account,
|
||||
);
|
||||
|
||||
@@ -111,17 +104,10 @@ class ConvertService
|
||||
$opportunity = $this->processOpportunity(
|
||||
lead: $lead,
|
||||
records: $records,
|
||||
duplicateCheck: $duplicateCheck,
|
||||
duplicateList: $duplicateList,
|
||||
skipSave: $skipSave,
|
||||
account: $account,
|
||||
contact: $contact,
|
||||
);
|
||||
|
||||
if ($duplicateCheck && count($duplicateList)) {
|
||||
throw ConflictSilent::createWithBody('duplicate', Json::encode($duplicateList));
|
||||
}
|
||||
|
||||
$lead->setStatus(Lead::STATUS_CONVERTED);
|
||||
|
||||
$this->entityManager->saveEntity($lead);
|
||||
@@ -280,19 +266,12 @@ class ConvertService
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object[] $duplicateList
|
||||
* @throws Forbidden
|
||||
* @throws BadRequest
|
||||
* @throws Conflict
|
||||
*/
|
||||
private function processAccount(
|
||||
Lead $lead,
|
||||
Values $records,
|
||||
bool $duplicateCheck,
|
||||
array &$duplicateList,
|
||||
bool &$skipSave,
|
||||
): ?Account {
|
||||
|
||||
private function processAccount(Lead $lead, Values $records): ?Account
|
||||
{
|
||||
if (!$records->has(Account::ENTITY_TYPE)) {
|
||||
return null;
|
||||
}
|
||||
@@ -305,35 +284,14 @@ class ConvertService
|
||||
|
||||
$service = $this->recordServiceContainer->getByClass(Account::class);
|
||||
|
||||
$account = $this->entityManager->getRDBRepositoryByClass(Account::class)->getNew();
|
||||
$account->set($values);
|
||||
|
||||
if ($duplicateCheck) {
|
||||
foreach ($service->findDuplicates($account) ?? [] as $e) {
|
||||
$duplicateList[] = (object) [
|
||||
'id' => $e->getId(),
|
||||
'name' => $e->getName(),
|
||||
'_entityType' => $e->getEntityType(),
|
||||
];
|
||||
|
||||
$skipSave = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($skipSave) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
$account = $service->create($values, CreateParams::create()->withSkipDuplicateCheck());
|
||||
|
||||
$lead->set('createdAccountId', $account->getId());
|
||||
$lead->setCreatedAccount($account);
|
||||
|
||||
return $account;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object[] $duplicateList
|
||||
* @throws Forbidden
|
||||
* @throws BadRequest
|
||||
* @throws Conflict
|
||||
@@ -341,9 +299,6 @@ class ConvertService
|
||||
private function processContact(
|
||||
Lead $lead,
|
||||
Values $records,
|
||||
bool $duplicateCheck,
|
||||
array &$duplicateList,
|
||||
bool &$skipSave,
|
||||
?Account $account,
|
||||
): ?Contact {
|
||||
|
||||
@@ -363,25 +318,6 @@ class ConvertService
|
||||
|
||||
$service = $this->recordServiceContainer->getByClass(Contact::class);
|
||||
|
||||
$contact = $this->entityManager->getRDBRepositoryByClass(Contact::class)->getNew();
|
||||
$contact->set($values);
|
||||
|
||||
if ($duplicateCheck) {
|
||||
foreach ($service->findDuplicates($contact) ?? [] as $e) {
|
||||
$duplicateList[] = (object) [
|
||||
'id' => $e->getId(),
|
||||
'name' => $e->getName(),
|
||||
'_entityType' => $e->getEntityType(),
|
||||
];
|
||||
|
||||
$skipSave = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($skipSave) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$contact = $service->create($values, CreateParams::create()->withSkipDuplicateCheck());
|
||||
|
||||
$lead->set('createdContactId', $contact->getId());
|
||||
@@ -391,14 +327,13 @@ class ConvertService
|
||||
$contact->getAccount() &&
|
||||
!$contact->getAccount()->get('originalLeadId')
|
||||
) {
|
||||
$lead->set('createdAccountId', $contact->getAccount()->getId());
|
||||
$lead->setCreatedAccount($contact->getAccount());
|
||||
}
|
||||
|
||||
return $contact;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object[] $duplicateList
|
||||
* @throws Forbidden
|
||||
* @throws BadRequest
|
||||
* @throws Conflict
|
||||
@@ -406,9 +341,6 @@ class ConvertService
|
||||
private function processOpportunity(
|
||||
Lead $lead,
|
||||
Values $records,
|
||||
bool $duplicateCheck,
|
||||
array &$duplicateList,
|
||||
bool &$skipSave,
|
||||
?Account $account,
|
||||
?Contact $contact,
|
||||
): ?Opportunity {
|
||||
@@ -433,30 +365,10 @@ class ConvertService
|
||||
|
||||
$service = $this->recordServiceContainer->getByClass(Opportunity::class);
|
||||
|
||||
$opportunity = $this->entityManager->getRDBRepositoryByClass(Opportunity::class)->getNew();
|
||||
$opportunity->set($values);
|
||||
|
||||
if ($duplicateCheck) {
|
||||
foreach ($service->findDuplicates($opportunity) ?? [] as $e) {
|
||||
$duplicateList[] = (object) [
|
||||
'id' => $e->getId(),
|
||||
'name' => $e->getName(),
|
||||
'_entityType' => $e->getEntityType(),
|
||||
];
|
||||
|
||||
$skipSave = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($skipSave) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$opportunity = $service->create($values, CreateParams::create()->withSkipDuplicateCheck());
|
||||
|
||||
if ($contact) {
|
||||
$this->entityManager
|
||||
->getRDBRepository(Contact::ENTITY_TYPE)
|
||||
->getRelation($contact, 'opportunities')
|
||||
->relate($opportunity);
|
||||
}
|
||||
@@ -532,7 +444,6 @@ class ConvertService
|
||||
foreach ($calls as $call) {
|
||||
if ($contact && $contact->hasId()) {
|
||||
$this->entityManager
|
||||
->getRDBRepository(Call::ENTITY_TYPE)
|
||||
->getRelation($call, 'contacts')
|
||||
->relate($contact);
|
||||
}
|
||||
@@ -579,14 +490,12 @@ class ConvertService
|
||||
foreach ($documents as $document) {
|
||||
if ($account && $account->hasId()) {
|
||||
$this->entityManager
|
||||
->getRDBRepository(Document::ENTITY_TYPE)
|
||||
->getRelation($document, 'accounts')
|
||||
->relate($account);
|
||||
}
|
||||
|
||||
if ($opportunity && $opportunity->hasId()) {
|
||||
$this->entityManager
|
||||
->getRDBRepository(Document::ENTITY_TYPE)
|
||||
->getRelation($document, 'opportunities')
|
||||
->relate($opportunity);
|
||||
}
|
||||
@@ -637,4 +546,63 @@ class ConvertService
|
||||
|
||||
return $account;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Conflict
|
||||
*/
|
||||
private function processDuplicateCheck(Values $records): void
|
||||
{
|
||||
$duplicateList = [];
|
||||
|
||||
if ($records->has(Account::ENTITY_TYPE)) {
|
||||
$accountService = $this->recordServiceContainer->getByClass(Account::class);
|
||||
|
||||
$account = $this->entityManager->getRDBRepositoryByClass(Account::class)->getNew();
|
||||
$account->set($records->get(Account::ENTITY_TYPE));
|
||||
|
||||
foreach ($accountService->findDuplicates($account) ?? [] as $e) {
|
||||
$duplicateList[] = (object) [
|
||||
'id' => $e->getId(),
|
||||
'name' => $e->getName(),
|
||||
'_entityType' => $e->getEntityType(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if ($records->has(Contact::ENTITY_TYPE)) {
|
||||
$contactService = $this->recordServiceContainer->getByClass(Contact::class);
|
||||
|
||||
$contact = $this->entityManager->getRDBRepositoryByClass(Contact::class)->getNew();
|
||||
$contact->set($records->get(Contact::ENTITY_TYPE));
|
||||
|
||||
foreach ($contactService->findDuplicates($contact) ?? [] as $e) {
|
||||
$duplicateList[] = (object) [
|
||||
'id' => $e->getId(),
|
||||
'name' => $e->getName(),
|
||||
'_entityType' => $e->getEntityType(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if ($records->has(Opportunity::ENTITY_TYPE)) {
|
||||
$opportunityService = $this->recordServiceContainer->getByClass(Opportunity::class);
|
||||
|
||||
$opportunity = $this->entityManager->getRDBRepositoryByClass(Opportunity::class)->getNew();
|
||||
$opportunity->set($records->get(Opportunity::ENTITY_TYPE));
|
||||
|
||||
foreach ($opportunityService->findDuplicates($opportunity) ?? [] as $e) {
|
||||
$duplicateList[] = (object) [
|
||||
'id' => $e->getId(),
|
||||
'name' => $e->getName(),
|
||||
'_entityType' => $e->getEntityType(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if (!count($duplicateList)) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw ConflictSilent::createWithBody('duplicate', Json::encode($duplicateList));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,13 +186,21 @@ class Email extends Database implements
|
||||
return;
|
||||
}
|
||||
|
||||
$setFetched = !$entity->isAttributeChanged($type . 'EmailAddressesNames');
|
||||
|
||||
$addresses = [];
|
||||
|
||||
foreach (get_object_vars($names) as $address) {
|
||||
$addresses[] = $address;
|
||||
}
|
||||
|
||||
$entity->set($type, implode(';', $addresses));
|
||||
$value = implode(';', $addresses);
|
||||
|
||||
$entity->set($type, $value);
|
||||
|
||||
if ($setFetched) {
|
||||
$entity->setFetched($type, $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -289,6 +297,10 @@ class Email extends Database implements
|
||||
$entity->set('nameHash', $nameHash);
|
||||
$entity->set('typeHash', $typeHash);
|
||||
$entity->set('idHash', $idHash);
|
||||
|
||||
$entity->setFetched('nameHash', $nameHash);
|
||||
$entity->setFetched('typeHash', $typeHash);
|
||||
$entity->setFetched('idHash', $idHash);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,16 +27,14 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
// To add aliases for backward compatibility.
|
||||
// Aliases for backward compatibility or patches.
|
||||
$map = [
|
||||
'Espo\\Core\\Hook\\Deprecations\\BaseHook' => 'Espo\\Core\\Hooks\\Base',
|
||||
'Espo\\Core\\Hooks\\Base' => 'Espo\\Core\\Hook\\Deprecations\\BaseHook',
|
||||
'Doctrine\\DBAL\\Platforms\\Keywords\\MariaDb102Keywords' => 'Espo\\Core\\Utils\\Database\\Dbal\\Platforms\\Keywords\\MariaDb102Keywords',
|
||||
];
|
||||
|
||||
/** @phpstan-ignore-next-line */
|
||||
foreach ($map as $item) {
|
||||
$className = $item[0];
|
||||
$alias = $item[1];
|
||||
|
||||
foreach ($map as $alias => $className) {
|
||||
if (!class_exists($className)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -631,6 +631,11 @@
|
||||
"insertText": "ext\\oauth\\getAccessToken(ID)",
|
||||
"returnType": "string",
|
||||
"unsafe": true
|
||||
},
|
||||
{
|
||||
"name": "ext\\appSecret\\get",
|
||||
"insertText": "ext\\appSecret\\get(STRING)",
|
||||
"returnType": "string"
|
||||
}
|
||||
],
|
||||
"functionClassNameMap": {
|
||||
@@ -642,6 +647,7 @@
|
||||
"ext\\acl\\checkScope": "Espo\\Core\\Formula\\Functions\\ExtGroup\\AclGroup\\CheckScopeType",
|
||||
"ext\\acl\\getLevel": "Espo\\Core\\Formula\\Functions\\ExtGroup\\AclGroup\\GetLevelType",
|
||||
"ext\\acl\\getPermissionLevel": "Espo\\Core\\Formula\\Functions\\ExtGroup\\AclGroup\\GetPermissionLevelType",
|
||||
"ext\\appSecret\\get": "Espo\\Core\\Formula\\Functions\\ExtGroup\\SecretGroup\\GetType",
|
||||
"util\\base64Encode": "Espo\\Core\\Formula\\Functions\\UtilGroup\\Base64EncodeType",
|
||||
"util\\base64Decode": "Espo\\Core\\Formula\\Functions\\UtilGroup\\Base64DecodeType",
|
||||
"ext\\oauth\\getAccessToken": "Espo\\Core\\Formula\\Functions\\ExtGroup\\OauthGroup\\GetAccessTokenType"
|
||||
|
||||
@@ -89,6 +89,10 @@
|
||||
{
|
||||
"type": "isTrue",
|
||||
"attribute": "ldapAuth"
|
||||
}, {
|
||||
"type": "equals",
|
||||
"attribute": "authenticationMethod",
|
||||
"value": "LDAP"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -2,21 +2,25 @@
|
||||
"fields": {
|
||||
"name": {
|
||||
"type": "varchar",
|
||||
"required": true
|
||||
"required": true,
|
||||
"audited": true
|
||||
},
|
||||
"subject": {
|
||||
"type": "varchar"
|
||||
"type": "varchar",
|
||||
"audited": true
|
||||
},
|
||||
"body": {
|
||||
"type": "wysiwyg",
|
||||
"view": "views/email-template/fields/body",
|
||||
"useIframe": true,
|
||||
"attachmentField": "attachments"
|
||||
"attachmentField": "attachments",
|
||||
"audited": true
|
||||
},
|
||||
"isHtml": {
|
||||
"type": "bool",
|
||||
"default": true,
|
||||
"inlineEditDisabled": true
|
||||
"inlineEditDisabled": true,
|
||||
"audited": true
|
||||
},
|
||||
"status": {
|
||||
"type": "enum",
|
||||
@@ -28,7 +32,8 @@
|
||||
"style": {
|
||||
"Inactive": "info"
|
||||
},
|
||||
"maxLength": 8
|
||||
"maxLength": 8,
|
||||
"audited": true
|
||||
},
|
||||
"oneOff": {
|
||||
"type": "bool",
|
||||
@@ -36,7 +41,8 @@
|
||||
"tooltip": true
|
||||
},
|
||||
"attachments": {
|
||||
"type": "attachmentMultiple"
|
||||
"type": "attachmentMultiple",
|
||||
"audited": true
|
||||
},
|
||||
"category": {
|
||||
"type": "link",
|
||||
@@ -47,7 +53,8 @@
|
||||
"view": "views/fields/assigned-user"
|
||||
},
|
||||
"teams": {
|
||||
"type": "linkMultiple"
|
||||
"type": "linkMultiple",
|
||||
"audited": true
|
||||
},
|
||||
"createdAt": {
|
||||
"type": "datetime",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"stylesheet": "client/css/espo/hazyblue.css",
|
||||
"stylesheetIframe": "client/css/espo/hazyblue-iframe.css",
|
||||
"logo": "client/img/logo-hazy.svg",
|
||||
"logo": "client/img/logo-light.svg",
|
||||
"textColor": "#333",
|
||||
"chartGridColor": "#ddd",
|
||||
"chartTickColor": "#e8eced",
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
namespace Espo\Tools\EntityManager;
|
||||
|
||||
use Espo\Core\Exceptions\Error;
|
||||
use Espo\Core\Name\Field;
|
||||
use Espo\Core\Utils\Config;
|
||||
use Espo\Core\Utils\Metadata;
|
||||
@@ -379,4 +380,20 @@ class NameUtil
|
||||
{
|
||||
return (bool) $this->metadata->get("entityDefs.$entityType.links.$name");
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 9.2.4
|
||||
*/
|
||||
public function linkNameIsBad(string $name): bool
|
||||
{
|
||||
if ($name === '') {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (preg_match('/[^a-z]/', $name[0])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->nameIsBad(ucfirst($name));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,8 +139,11 @@ class LinkManager
|
||||
throw new Error("Relation name is too long.");
|
||||
}
|
||||
|
||||
if (preg_match('/[^a-z]/', $relationName[0])) {
|
||||
throw new Error("Relation name should start with a lower case letter.");
|
||||
if ($this->nameUtil->linkNameIsBad($relationName)) {
|
||||
$message = "Relation name should contain only letters and numbers, " .
|
||||
"start with a lower case letter.";
|
||||
|
||||
throw new Error($message);
|
||||
}
|
||||
|
||||
if ($this->metadata->get(['scopes', ucfirst($relationName)])) {
|
||||
@@ -180,6 +183,13 @@ class LinkManager
|
||||
throw new Error("Link name is too long.");
|
||||
}
|
||||
|
||||
if ($this->nameUtil->linkNameIsBad($link) || $this->nameUtil->linkNameIsBad($linkForeign)) {
|
||||
$message = "Link name should contain only letters and numbers, " .
|
||||
"start with a lower case letter.";
|
||||
|
||||
throw new Error($message);
|
||||
}
|
||||
|
||||
if (preg_match('/[^a-z]/', $link[0])) {
|
||||
throw new Error("Link name should start with a lower case letter.");
|
||||
}
|
||||
|
||||
@@ -67,8 +67,8 @@ class TokensProvider
|
||||
if (
|
||||
$account->getRefreshToken() &&
|
||||
$account->getExpiresAt() &&
|
||||
$account->getExpiresAt()->isGreaterThan(
|
||||
DateTime::createNow()->addSeconds(- self::EXPIRATION_LEAD_TIME)
|
||||
$account->getExpiresAt()->isLessThan(
|
||||
DateTime::createNow()->addSeconds(self::EXPIRATION_LEAD_TIME)
|
||||
)
|
||||
) {
|
||||
$this->refresh($account);
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="318" height="78" enable-background="new 0 0 307.813 75" overflow="visible" version="1.1" viewBox="0 0 318 78" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
|
||||
<switch transform="matrix(1.089 0 0 1.089 -.89733 -.52658)">
|
||||
<foreignObject width="1" height="1" requiredExtensions="http://ns.adobe.com/AdobeIllustrator/10.0/">
|
||||
</foreignObject>
|
||||
<g transform="matrix(.96767 0 0 .96767 3.9659 -1.2011)">
|
||||
<path d="m169.53 21.864c-7.453 2.972-9.569 11.987-9.005 19.212 1.587 2.982 3.845 5.562 5.783 8.312l4.262-1.083c-1.796-4.447-1.689-9.424-0.806-14.066 0.585-3.001 2.309-6.476 5.634-7.032 5.307-0.847 10.733-0.271 16.088-0.369 0.091-2.196 0.115-4.392 0.107-6.585-7.333 0.387-15.043-1.038-22.063 1.611zm52.714-1.294c-8.12-0.952-16.332-0.149-24.492-0.387-0.021 6.43-3e-3 12.854 0.078 19.274 2.625-0.849 5.251-1.739 7.909-2.532 0.042-3.272 0.028-6.527-0.071-9.789 4.869-0.029 9.874-0.757 14.639 0.451 1.838 0.298 2.051 2.25 2.687 3.641 2.541-0.891 5.111-1.717 7.672-2.574-0.703-4.246-4.129-7.633-8.422-8.084zm23.522-0.593c-3.954 0.072-7.912 0.064-11.864 0.047 0.051 2.544 0.063 5.074 0.072 7.617 4.263-1.482 8.553-2.889 12.848-4.268-0.35-1.128-0.706-2.268-1.056-3.396z" fill="#75797c"/>
|
||||
<path d="m161.96 69.125c7.886-3.717 15.757-7.463 23.72-11.018 5.563 0.359 11.146 0.021 16.722 0.193 1.14-0.036 2.292-0.061 3.432-0.088-0.011-3.195-0.025-6.38-0.082-9.564 3.428-1.502 10.227-4.623 10.227-4.623l15.215 13.941 11.096 0.106-0.715-26.236 0.803-0.211 9.005 26.344 8.834-0.066 8.99-28.394-0.308 28.434 8.074-0.021-0.231-37.932-9.279 0.071 30.625-14.141s-37.593 14.279-56.404 21.385c-2.996 1.022-5.878 2.315-8.853 3.394-2.278 0.867-4.558 1.713-6.834 2.58-20.071 7.526-39.945 15.604-60.126 22.803-6.777-10.522-15.314-19.854-21.768-30.585zm72.116-17.961c-0.108 0.154-0.324 0.458-0.429 0.611-3.448-3.018-6.765-6.189-10.21-9.205 1.745-1.096 3.47-2.242 5.026-3.597 1.625-1.386 3.479-2.469 5.345-3.499 0.293 5.227 0.258 10.452 0.268 15.69zm23.942-9.67c-0.857 2.578-1.825 5.137-2.793 7.682-1.644-6.217-3.94-12.238-5.856-18.383-0.119-0.52-0.366-1.574-0.487-2.093 3.428-1.709 10.585-4.854 15.229-6.815-1.647 5.969-4.306 14.029-6.093 19.609z" fill="#ddaf28"/>
|
||||
<g fill="#75797c">
|
||||
<path d="m45.672 58.148h-18.526c-2.861 0-5.614-0.651-8.257-1.953-2.861-1.409-5.043-3.651-6.547-6.725-1.503-3.074-2.254-6.455-2.254-10.145 0-3.652 0.724-6.961 2.173-9.926 1.594-3.219 3.803-5.569 6.628-7.052 1.557-0.795 3.052-1.355 4.482-1.682 1.43-0.325 3.07-0.488 4.917-0.488h17.168v6.789h-15.886c-1.415 0-2.602 0.187-3.563 0.558-0.961 0.372-1.912 1.037-2.855 1.994s-1.597 1.887-1.959 2.791c-0.363 0.902-0.543 2.027-0.543 3.375h25.023v6.789h-25.025c0 1.24 0.164 2.325 0.491 3.256 0.327 0.93 0.919 1.887 1.776 2.871 0.856 0.985 1.749 1.732 2.677 2.242 0.929 0.512 2.03 0.767 3.306 0.767h16.774z"/>
|
||||
<path d="m76.499 49.519c0 2.397-0.771 4.449-2.312 6.154-1.541 1.706-3.49 2.56-5.846 2.56h-18.653v-5.113h15.326c1.087 0 2.001-0.272 2.744-0.817s1.115-1.327 1.115-2.345c0-2.362-1.595-3.543-4.783-3.543h-7.825c-1.666 0-3.278-0.79-4.836-2.369-1.559-1.58-2.336-3.287-2.336-5.119 0-2.585 0.579-4.667 1.738-6.248 1.34-1.794 3.313-2.692 5.922-2.692h17.928v5.364h-15.938c-0.614 0-1.147 0.289-1.599 0.868s-0.677 1.235-0.677 1.972c0 0.807 0.298 1.498 0.896 2.076 0.597 0.579 1.311 0.867 2.144 0.867h8.415c2.643 0 4.733 0.79 6.271 2.369 1.536 1.579 2.306 3.584 2.306 6.016z"/>
|
||||
<path d="m109.29 43.414c0 4.495-1.166 8.074-3.497 10.738s-5.395 3.996-9.188 3.996h-8.186v10.309h-7.627v-38.472h15.09c4.27 0 7.6 1.269 9.989 3.806 2.279 2.428 3.419 5.637 3.419 9.623zm-7.627 0.405c0-2.356-0.754-4.286-2.262-5.793-1.509-1.505-3.388-2.258-5.641-2.258h-5.341v16.429h5.886c2.179 0 3.951-0.771 5.313-2.313 1.363-1.54 2.045-3.562 2.045-6.065z"/>
|
||||
<path d="m145.1 43.967c0 4.896-1.557 8.65-4.669 11.261-2.86 2.394-6.751 3.591-11.673 3.591-4.923 0-8.742-1.087-11.456-3.264-3.15-2.502-4.724-6.401-4.724-11.696 0-4.424 1.701-7.906 5.104-10.446 3.04-2.283 6.786-3.427 11.238-3.427 4.887 0 8.805 1.225 11.754 3.673s4.426 5.884 4.426 10.308zm-8.382-0.065c0-2.285-0.716-4.197-2.146-5.738-1.432-1.54-3.379-2.312-5.841-2.312-2.246 0-4.103 0.79-5.57 2.366-1.467 1.577-2.2 3.563-2.2 5.955 0 2.756 0.743 4.949 2.228 6.581s3.405 2.448 5.76 2.448c2.679 0 4.673-0.852 5.977-2.557 1.193-1.557 1.792-3.805 1.792-6.743z"/>
|
||||
</g>
|
||||
</g>
|
||||
</switch>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 4.3 KiB |
@@ -26,12 +26,8 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
define('crm:views/knowledge-base-article/record/detail-quick', ['views/record/detail-small'], function (Dep) {
|
||||
import DetailRecordView from 'views/record/detail';
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
isWide: true,
|
||||
sideView: false,
|
||||
});
|
||||
});
|
||||
export default class extends DetailRecordView {
|
||||
|
||||
}
|
||||
|
||||
@@ -26,11 +26,8 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
define('crm:views/knowledge-base-article/record/edit-quick', ['views/record/edit-small'], function (Dep) {
|
||||
import EditRecordView from 'views/record/edit';
|
||||
|
||||
return Dep.extend({
|
||||
export default class extends EditRecordView {
|
||||
|
||||
isWide: true,
|
||||
sideView: false,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,30 +1,40 @@
|
||||
<div class="panel panel-default no-side-margin">
|
||||
<div class="panel-body">
|
||||
<div class="row">
|
||||
<div class="cell form-group col-md-6" data-name="currentPassword">
|
||||
<label
|
||||
class="control-label"
|
||||
data-name="currentPassword"
|
||||
>{{translate 'currentPassword' scope='User' category='fields'}}</label>
|
||||
<div class="field" data-name="currentPassword">{{{currentPassword}}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="cell form-group col-md-6" data-name="password">
|
||||
<label
|
||||
class="control-label"
|
||||
data-name="password"
|
||||
>{{translate 'newPassword' scope='User' category='fields'}}</label>
|
||||
<div class="field" data-name="password">{{{password}}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="cell form-group col-md-6" data-name="passwordConfirm">
|
||||
<label
|
||||
class="control-label"
|
||||
data-name="passwordConfirm"
|
||||
>{{translate 'passwordConfirm' scope='User' category='fields'}}</label>
|
||||
<div class="field" data-name="passwordConfirm">{{{passwordConfirm}}}</div>
|
||||
<div class="no-side-margin record">
|
||||
<div>
|
||||
<div class="record-grid-wide">
|
||||
<div class="left">
|
||||
<div class="middle">
|
||||
<div class="panel panel-default first last">
|
||||
<div class="panel-body panel-body-form">
|
||||
<div class="row">
|
||||
<div class="cell form-group col-md-6" data-name="currentPassword">
|
||||
<label
|
||||
class="control-label"
|
||||
data-name="currentPassword"
|
||||
>{{translate 'currentPassword' scope='User' category='fields'}}</label>
|
||||
<div class="field" data-name="currentPassword">{{{currentPassword}}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="cell form-group col-md-6" data-name="password">
|
||||
<label
|
||||
class="control-label"
|
||||
data-name="password"
|
||||
>{{translate 'newPassword' scope='User' category='fields'}}</label>
|
||||
<div class="field" data-name="password">{{{password}}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="cell form-group col-md-6" data-name="passwordConfirm">
|
||||
<label
|
||||
class="control-label"
|
||||
data-name="passwordConfirm"
|
||||
>{{translate 'passwordConfirm' scope='User' category='fields'}}</label>
|
||||
<div class="field" data-name="passwordConfirm">{{{passwordConfirm}}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,26 +1,37 @@
|
||||
<div class="panel panel-default no-side-margin">
|
||||
<div class="panel-body panel-body-form">
|
||||
<div class="row">
|
||||
<div class="cell form-group col-md-6" data-name="dashboardTabList">
|
||||
<label
|
||||
class="control-label"
|
||||
data-name="dashboardTabList"
|
||||
>{{translate 'dashboardTabList' category='fields' scope="Preferences"}}</label>
|
||||
<div class="field" data-name="dashboardTabList">
|
||||
{{{dashboardTabList}}}
|
||||
</div>
|
||||
</div>
|
||||
{{#if hasLocked}}
|
||||
<div class="cell form-group col-md-6" data-name="dashboardLocked">
|
||||
<label
|
||||
class="control-label"
|
||||
data-name="dashboardLocked"
|
||||
>{{translate 'dashboardLocked' category='fields' scope="Preferences"}}</label>
|
||||
<div class="field" data-name="dashboardLocked">
|
||||
{{{dashboardLocked}}}
|
||||
<div class="no-side-margin record">
|
||||
<div>
|
||||
<div class="record-grid-wide">
|
||||
<div class="left">
|
||||
<div class="middle">
|
||||
<div class="panel panel-default first last">
|
||||
<div class="panel-body panel-body-form">
|
||||
<div class="row">
|
||||
<div class="cell form-group col-md-6" data-name="dashboardTabList">
|
||||
<label
|
||||
class="control-label"
|
||||
data-name="dashboardTabList"
|
||||
>{{translate 'dashboardTabList' category='fields' scope="Preferences"}}</label>
|
||||
<div class="field" data-name="dashboardTabList">
|
||||
{{{dashboardTabList}}}
|
||||
</div>
|
||||
</div>
|
||||
{{#if hasLocked}}
|
||||
<div class="cell form-group col-md-6" data-name="dashboardLocked">
|
||||
<label
|
||||
class="control-label"
|
||||
data-name="dashboardLocked"
|
||||
>{{translate 'dashboardLocked' category='fields' scope="Preferences"}}</label>
|
||||
<div class="field" data-name="dashboardLocked">
|
||||
{{{dashboardLocked}}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -25,9 +25,11 @@
|
||||
role="button"
|
||||
tabindex="0"
|
||||
data-action="expandDetails"
|
||||
class="text-soft"
|
||||
><span class="fas fa-chevron-down"></span></a><span style="user-select: none"> </span>
|
||||
<span class="fields text-muted small">{{fieldsString}}</span>
|
||||
class="text-muted no-underline"
|
||||
><span class="fas fa-chevron-down text-soft" data-role="icon"></span>
|
||||
<span style="user-select: none"> </span>
|
||||
<span class="fields small">{{fieldsString}}</span>
|
||||
</a>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="buttons-panel margin hide floated-row clearfix">
|
||||
<div>
|
||||
<button class="btn btn-primary btn-xs-wide post">{{translate 'Post'}}</button>
|
||||
{{#if allowInternalNotes}}
|
||||
{{~#if allowInternalNotes~}}
|
||||
<span
|
||||
style="cursor: pointer;"
|
||||
class="internal-mode-switcher{{#if isInternalNoteMode}} enabled{{/if}} action"
|
||||
@@ -12,7 +12,7 @@
|
||||
>
|
||||
<span class="fas fa-lock"></span>
|
||||
</span>
|
||||
{{/if}}
|
||||
{{~/if~}}
|
||||
</div>
|
||||
<div class="attachments-container">
|
||||
{{{attachments}}}
|
||||
|
||||
@@ -30,6 +30,12 @@
|
||||
|
||||
export default class {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
entityType
|
||||
|
||||
/**
|
||||
* @param {module:views/fields/base} view A field view.
|
||||
*/
|
||||
@@ -48,6 +54,8 @@ export default class {
|
||||
const entityType = metadata.get(['entityDefs', model.entityType, 'links', link, 'entity']) ||
|
||||
model.entityType;
|
||||
|
||||
this.entityType = entityType;
|
||||
|
||||
const fieldDefs = metadata.get(['entityDefs', entityType, 'fields', field]) || {};
|
||||
const type = fieldDefs.type;
|
||||
|
||||
@@ -78,4 +86,11 @@ export default class {
|
||||
getForeignParams() {
|
||||
return Espo.Utils.cloneDeep(this.foreignParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {string}
|
||||
*/
|
||||
getEntityType() {
|
||||
return this.entityType;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,6 +121,11 @@ Espo.Utils = {
|
||||
});
|
||||
}
|
||||
else if (typeof view[method] === 'function') {
|
||||
if (view?.events[`click [data-action="${action}"]`]) {
|
||||
// Prevents from firing if a handler is already assigned. Important.
|
||||
return false;
|
||||
}
|
||||
|
||||
view[method].call(view, data, event);
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
@@ -108,6 +108,7 @@ class View extends BullView {
|
||||
* @param {module:view~actionHandlerCallback} handler A handler.
|
||||
*/
|
||||
addActionHandler(action, handler) {
|
||||
// The key should be in sync with one in Utils.handleAction.
|
||||
const fullAction = `click [data-action="${action}"]`;
|
||||
|
||||
this.events[fullAction] = e => {
|
||||
|
||||
@@ -31,9 +31,6 @@ import Detail from 'views/email-template/record/detail';
|
||||
|
||||
export default class extends EditRecordView {
|
||||
|
||||
isWide = true
|
||||
sideView = false
|
||||
|
||||
setup() {
|
||||
super.setup();
|
||||
Detail.prototype.listenToInsertField.call(this);
|
||||
|
||||
@@ -28,11 +28,31 @@
|
||||
|
||||
import ArrayFieldView from 'views/fields/array';
|
||||
import ForeignEnumFieldView from 'views/fields/foreign-enum';
|
||||
import Helper from 'helpers/misc/foreign-field';
|
||||
|
||||
class ForeignArrayFieldView extends ArrayFieldView {
|
||||
|
||||
type = 'foreign'
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
foreignEntityType
|
||||
|
||||
setup() {
|
||||
const helper = new Helper(this);
|
||||
const foreignParams = helper.getForeignParams();
|
||||
|
||||
for (const param in foreignParams) {
|
||||
this.params[param] = foreignParams[param];
|
||||
}
|
||||
|
||||
this.foreignEntityType = helper.getEntityType();
|
||||
|
||||
super.setup();
|
||||
}
|
||||
|
||||
setupOptions() {
|
||||
ForeignEnumFieldView.prototype.setupOptions.call(this);
|
||||
}
|
||||
|
||||
@@ -27,37 +27,34 @@
|
||||
************************************************************************/
|
||||
|
||||
import ChecklistFieldView from 'views/fields/checklist';
|
||||
import Helper from 'helpers/misc/foreign-field';
|
||||
import ForeignArrayFieldView from 'views/fields/foreign-array';
|
||||
|
||||
class ForeignChecklistFieldView extends ChecklistFieldView {
|
||||
|
||||
type = 'foreign'
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
foreignEntityType
|
||||
|
||||
setup() {
|
||||
const helper = new Helper(this);
|
||||
const foreignParams = helper.getForeignParams();
|
||||
|
||||
for (const param in foreignParams) {
|
||||
this.params[param] = foreignParams[param];
|
||||
}
|
||||
|
||||
this.foreignEntityType = helper.getEntityType();
|
||||
|
||||
super.setup();
|
||||
}
|
||||
|
||||
setupOptions() {
|
||||
this.params.options = [];
|
||||
|
||||
if (!this.params.field || !this.params.link) {
|
||||
return;
|
||||
}
|
||||
|
||||
const scope = this.getMetadata()
|
||||
.get(['entityDefs', this.model.entityType, 'links', this.params.link, 'entity']);
|
||||
|
||||
if (!scope) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.params.isSorted = this.getMetadata()
|
||||
.get(['entityDefs', scope, 'fields', this.params.field, 'isSorted']) || false;
|
||||
|
||||
this.params.options = this.getMetadata()
|
||||
.get(['entityDefs', scope, 'fields', this.params.field, 'options']) || [];
|
||||
|
||||
this.translatedOptions = {};
|
||||
|
||||
this.params.options.forEach(item => {
|
||||
this.translatedOptions[item] = this.getLanguage()
|
||||
.translateOption(item, this.params.field, scope);
|
||||
});
|
||||
ForeignArrayFieldView.prototype.setupOptions.call(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,14 +27,32 @@
|
||||
************************************************************************/
|
||||
|
||||
import EnumFieldView from 'views/fields/enum';
|
||||
import Helper from 'helpers/misc/foreign-field';
|
||||
|
||||
class ForeignEnumFieldView extends EnumFieldView {
|
||||
|
||||
type = 'foreign'
|
||||
|
||||
setupOptions() {
|
||||
this.params.options = [];
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
foreignEntityType
|
||||
|
||||
setup() {
|
||||
const helper = new Helper(this);
|
||||
const foreignParams = helper.getForeignParams();
|
||||
|
||||
for (const param in foreignParams) {
|
||||
this.params[param] = foreignParams[param];
|
||||
}
|
||||
|
||||
this.foreignEntityType = helper.getEntityType();
|
||||
|
||||
super.setup();
|
||||
}
|
||||
|
||||
setupOptions() {
|
||||
const field = this.params.field;
|
||||
const link = this.params.link;
|
||||
|
||||
@@ -42,47 +60,15 @@ class ForeignEnumFieldView extends EnumFieldView {
|
||||
return;
|
||||
}
|
||||
|
||||
const entityType = this.getMetadata().get(`entityDefs.${this.model.entityType}.links.${link}.entity`);
|
||||
|
||||
if (!entityType) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {{
|
||||
* optionsPath?: string|null,
|
||||
* optionsReference?: string|null,
|
||||
* translation?: string|null,
|
||||
* options?: string[],
|
||||
* isSorted?: boolean,
|
||||
* displayAsLabel?: boolean,
|
||||
* style?: Record,
|
||||
* labelType?: string,
|
||||
* }}
|
||||
*/
|
||||
const fieldDefs = this.getMetadata().get(`entityDefs.${entityType}.fields.${field}`);
|
||||
|
||||
if (!fieldDefs) {
|
||||
return;
|
||||
}
|
||||
|
||||
let {
|
||||
optionsPath,
|
||||
optionsReference,
|
||||
translation,
|
||||
options,
|
||||
isSorted,
|
||||
displayAsLabel,
|
||||
style,
|
||||
labelType,
|
||||
} = fieldDefs;
|
||||
let optionsPath = this.params.optionsPath;
|
||||
const optionsReference = this.params.optionsReference;
|
||||
let options = this.params.options;
|
||||
const style = this.params.style;
|
||||
|
||||
if (!optionsPath && optionsReference) {
|
||||
const [refEntityType, refField] = optionsReference.split('.');
|
||||
|
||||
optionsPath = `entityDefs.${refEntityType}.fields.${refField}.options`;
|
||||
|
||||
style = this.getMetadata().get(`entityDefs.${refEntityType}.fields.${refField}.style`) ?? {};
|
||||
}
|
||||
|
||||
if (optionsPath) {
|
||||
@@ -90,14 +76,10 @@ class ForeignEnumFieldView extends EnumFieldView {
|
||||
}
|
||||
|
||||
this.params.options = Espo.Utils.clone(options) ?? [];
|
||||
this.params.translation = translation;
|
||||
this.params.isSorted = isSorted ?? false;
|
||||
this.params.displayAsLabel = displayAsLabel ?? false;
|
||||
this.params.labelType = labelType;
|
||||
this.styleMap = style ?? {};
|
||||
|
||||
const pairs = this.params.options
|
||||
.map(item => [item, this.getLanguage().translateOption(item, field, entityType)])
|
||||
.map(item => [item, this.getLanguage().translateOption(item, field, this.foreignEntityType)])
|
||||
|
||||
this.translatedOptions = Object.fromEntries(pairs);
|
||||
}
|
||||
|
||||
@@ -28,11 +28,31 @@
|
||||
|
||||
import MultiEnumFieldView from 'views/fields/multi-enum';
|
||||
import ForeignArrayFieldView from 'views/fields/foreign-array';
|
||||
import Helper from 'helpers/misc/foreign-field';
|
||||
|
||||
class ForeignMultiEnumFieldView extends MultiEnumFieldView {
|
||||
|
||||
type = 'foreign'
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
foreignEntityType
|
||||
|
||||
setup() {
|
||||
const helper = new Helper(this);
|
||||
const foreignParams = helper.getForeignParams();
|
||||
|
||||
for (const param in foreignParams) {
|
||||
this.params[param] = foreignParams[param];
|
||||
}
|
||||
|
||||
this.foreignEntityType = helper.getEntityType();
|
||||
|
||||
super.setup();
|
||||
}
|
||||
|
||||
setupOptions() {
|
||||
ForeignArrayFieldView.prototype.setupOptions.call(this);
|
||||
}
|
||||
|
||||
@@ -119,6 +119,7 @@ class MasterSiteView extends View {
|
||||
}
|
||||
|
||||
body.dataset.isDark = this.getThemeManager().getParam('isDark') ?? false;
|
||||
body.dataset.themeName = this.getThemeManager().getName();
|
||||
|
||||
const footerView = this.getView('footer');
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ class UpdateNoteStreamView extends NoteStreamView {
|
||||
const statusValue = data.value;
|
||||
|
||||
this.statusStyle = this.getMetadata()
|
||||
.get(`entityDefs.${parentType}.fields.${statusField}.style.${statusValue}`) ||
|
||||
.get(`entityDefs.${parentType}.fields.${statusField}.style.${statusValue}`) ||
|
||||
'default';
|
||||
|
||||
this.statusText = this.getLanguage()
|
||||
@@ -101,7 +101,7 @@ class UpdateNoteStreamView extends NoteStreamView {
|
||||
|
||||
this.wait(true);
|
||||
|
||||
this.getModelFactory().create(parentType, model => {
|
||||
this.getModelFactory().create(parentType).then(model => {
|
||||
const modelWas = model;
|
||||
const modelBecame = model.clone();
|
||||
|
||||
@@ -116,7 +116,9 @@ class UpdateNoteStreamView extends NoteStreamView {
|
||||
|
||||
fields.forEach(field => {
|
||||
const type = model.getFieldType(field) || 'base';
|
||||
const viewName = this.getMetadata().get(['entityDefs', model.entityType, 'fields', field, 'view']) ||
|
||||
|
||||
const viewName = model.getFieldParam(field, 'auditView') ??
|
||||
model.getFieldParam(field, 'view') ??
|
||||
this.getFieldManager().getViewName(type);
|
||||
|
||||
const attributeList = this.getFieldManager().getEntityTypeFieldAttributeList(model.entityType, field);
|
||||
@@ -143,24 +145,26 @@ class UpdateNoteStreamView extends NoteStreamView {
|
||||
|
||||
this.createView(field + 'Was', viewName, {
|
||||
model: modelWas,
|
||||
name: field,
|
||||
readOnly: true,
|
||||
defs: {
|
||||
name: field
|
||||
},
|
||||
mode: 'detail',
|
||||
inlineEditDisabled: true,
|
||||
selector: `.row[data-name="${field}"] .cell-was`,
|
||||
auditData: {
|
||||
type: 'was',
|
||||
},
|
||||
});
|
||||
|
||||
this.createView(field + 'Became', viewName, {
|
||||
model: modelBecame,
|
||||
name: field,
|
||||
readOnly: true,
|
||||
defs: {
|
||||
name: field,
|
||||
},
|
||||
mode: 'detail',
|
||||
inlineEditDisabled: true,
|
||||
selector: `.row[data-name="${field}"] .cell-became`,
|
||||
auditData: {
|
||||
type: 'became',
|
||||
},
|
||||
});
|
||||
|
||||
this.fieldDataList.push({
|
||||
@@ -175,16 +179,17 @@ class UpdateNoteStreamView extends NoteStreamView {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
toggleDetails() {
|
||||
const target = this.element.querySelector('[data-action="expandDetails"]');
|
||||
|
||||
const $details = this.$el.find('> .details');
|
||||
const $fields = this.$el.find('> .stream-details-container > .fields');
|
||||
const detailsElement = this.element.querySelector(':scope > .details');
|
||||
const fieldElement = this.element.querySelector(':scope > .stream-details-container > .fields');
|
||||
|
||||
const iconElement = target.querySelector('[data-role="icon"]');
|
||||
|
||||
if (!this.isExpanded) {
|
||||
$details.removeClass('hidden');
|
||||
$fields.addClass('hidden');
|
||||
detailsElement.classList.remove('hidden');
|
||||
fieldElement?.classList.add('hidden');
|
||||
|
||||
this.fieldList.forEach(field => {
|
||||
const wasField = this.getView(field + 'Was');
|
||||
@@ -196,21 +201,19 @@ class UpdateNoteStreamView extends NoteStreamView {
|
||||
}
|
||||
});
|
||||
|
||||
$(target).find('span')
|
||||
.removeClass('fa-chevron-down')
|
||||
.addClass('fa-chevron-up');
|
||||
iconElement.classList.remove('fa-chevron-down');
|
||||
iconElement.classList.add('fa-chevron-up');
|
||||
|
||||
this.isExpanded = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$details.addClass('hidden');
|
||||
$fields.removeClass('hidden');
|
||||
detailsElement.classList.add('hidden');
|
||||
fieldElement?.classList.remove('hidden');
|
||||
|
||||
$(target).find('span')
|
||||
.addClass('fa-chevron-down')
|
||||
.removeClass('fa-chevron-up');
|
||||
iconElement.classList.remove('fa-chevron-up');
|
||||
iconElement.classList.add('fa-chevron-down');
|
||||
|
||||
this.isExpanded = false;
|
||||
}
|
||||
|
||||
@@ -63,26 +63,26 @@ class UserGeneratePasswordFieldView extends BaseFieldView {
|
||||
|
||||
this.strengthParams = this.options.strengthParams || {};
|
||||
|
||||
this.passwordStrengthLength = this.strengthParams.passwordStrengthLength ||
|
||||
this.getConfig().get('passwordStrengthLength');
|
||||
this.passwordStrengthLength = this.strengthParams.passwordStrengthLength ??
|
||||
this.getConfig().get('passwordStrengthLength') ?? null;
|
||||
|
||||
this.passwordStrengthLetterCount = this.strengthParams.passwordStrengthLetterCount ||
|
||||
this.getConfig().get('passwordStrengthLetterCount');
|
||||
this.passwordStrengthLetterCount = this.strengthParams.passwordStrengthLetterCount ??
|
||||
this.getConfig().get('passwordStrengthLetterCount') ?? null;
|
||||
|
||||
this.passwordStrengthNumberCount = this.strengthParams.passwordStrengthNumberCount ||
|
||||
this.getConfig().get('passwordStrengthNumberCount');
|
||||
this.passwordStrengthNumberCount = this.strengthParams.passwordStrengthNumberCount ??
|
||||
this.getConfig().get('passwordStrengthNumberCount') ?? null;
|
||||
|
||||
this.passwordStrengthSpecialCharacterCount = this.strengthParams.passwordStrengthSpecialCharacterCount ||
|
||||
this.getConfig().get('passwordStrengthSpecialCharacterCount');
|
||||
this.passwordStrengthSpecialCharacterCount = this.strengthParams.passwordStrengthSpecialCharacterCount ??
|
||||
this.getConfig().get('passwordStrengthSpecialCharacterCount') ?? null;
|
||||
|
||||
this.passwordGenerateLength = this.strengthParams.passwordGenerateLength ||
|
||||
this.getConfig().get('passwordGenerateLength');
|
||||
this.passwordGenerateLength = this.strengthParams.passwordGenerateLength ??
|
||||
this.getConfig().get('passwordGenerateLength') ?? null;
|
||||
|
||||
this.passwordGenerateLetterCount = this.strengthParams.passwordGenerateLetterCount ||
|
||||
this.getConfig().get('passwordGenerateLetterCount');
|
||||
this.passwordGenerateLetterCount = this.strengthParams.passwordGenerateLetterCount ??
|
||||
this.getConfig().get('passwordGenerateLetterCount') ?? null;
|
||||
|
||||
this.passwordGenerateNumberCount = this.strengthParams.passwordGenerateNumberCount ||
|
||||
this.getConfig().get('passwordGenerateNumberCount');
|
||||
this.passwordGenerateNumberCount = this.strengthParams.passwordGenerateNumberCount ??
|
||||
this.getConfig().get('passwordGenerateNumberCount') ?? null;
|
||||
}
|
||||
|
||||
fetch() {
|
||||
|
||||
@@ -106,6 +106,7 @@
|
||||
@dropdown-link-hover-bg-value: @navbar-inverse-link-hover-bg-value;
|
||||
@dropdown-divider-bg-value: @default-border-color-value;
|
||||
@dropdown-border-value: @panel-default-border-value;
|
||||
@dropdown-link-active-bg-value: lighten(@navbar-inverse-link-hover-bg-value, 3%);
|
||||
|
||||
@select-item-bg-value: @table-bg-accent-value;
|
||||
@select-item-border-value: @btn-default-border-value;
|
||||
|
||||
+15
-289
@@ -448,10 +448,6 @@ input.numeric-text {
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.filter .selectize-input {
|
||||
min-height: var(--input-height-small);
|
||||
}
|
||||
|
||||
.btn.active {
|
||||
box-shadow: none;
|
||||
}
|
||||
@@ -642,60 +638,6 @@ input.global-search-input {
|
||||
margin-right: var(--panel-padding);
|
||||
}
|
||||
|
||||
.cell > .field {
|
||||
overflow-wrap: break-word;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.field .row {
|
||||
margin-left: calc(var(--3px) * -1) !important;
|
||||
margin-right: calc(var(--3px) * -1) !important;
|
||||
|
||||
> div {
|
||||
padding-left: var(--3px) !important;
|
||||
padding-right: var(--3px) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.field .form-control,
|
||||
.field .btn {
|
||||
margin-bottom: var(--3px);
|
||||
}
|
||||
|
||||
.field .input-group .form-control,
|
||||
.field .input-group .btn {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.field .input-group {
|
||||
margin-bottom: var(--3px);
|
||||
}
|
||||
|
||||
.field .link-container {
|
||||
margin-bottom: 0;
|
||||
|
||||
&:not(.no-input) {
|
||||
> .list-group-item:last-child {
|
||||
border-bottom-width: 0;
|
||||
}
|
||||
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
|
||||
> .list-group-item:last-child {
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
border-bottom-width: 0;
|
||||
}
|
||||
}
|
||||
|
||||
> .list-group-item {
|
||||
.text:empty:before {
|
||||
content: "\200b";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.list-group {
|
||||
border-radius: var(--border-radius);
|
||||
|
||||
@@ -798,20 +740,6 @@ input.global-search-input {
|
||||
}
|
||||
}
|
||||
|
||||
.field {
|
||||
.list-group .list-group-item {
|
||||
background-color: var(--panel-bg);
|
||||
}
|
||||
|
||||
.list-group {
|
||||
background-color: var(--default-border-color);
|
||||
}
|
||||
}
|
||||
|
||||
.panel-body .field > .link-container > .list-group-item {
|
||||
background-color: @panel-bg;
|
||||
}
|
||||
|
||||
.panel-body .list-group-item {
|
||||
background-color: @panel-bg;
|
||||
|
||||
@@ -820,214 +748,6 @@ input.global-search-input {
|
||||
}
|
||||
}
|
||||
|
||||
.field {
|
||||
.link-container {
|
||||
.list-group-item {
|
||||
> div {
|
||||
margin: calc(var(--6px) * -1) 0 calc(var(--6px) * -1);
|
||||
}
|
||||
|
||||
> div > div {
|
||||
margin: var(--6px) 0;
|
||||
}
|
||||
|
||||
.form-control,
|
||||
.btn {
|
||||
margin-top: var(--2px);
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
> span.text {
|
||||
width: calc(100% - var(--18px));
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
> span.drag-handle {
|
||||
display: inline-block;
|
||||
width: var(--18px);
|
||||
color: var(--text-muted-color);
|
||||
cursor: grab;
|
||||
vertical-align: top;
|
||||
|
||||
&:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
}
|
||||
|
||||
> span.item-button {
|
||||
display: inline-block;
|
||||
width: var(--18px);
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
&:has(> .item-button) {
|
||||
> span.text {
|
||||
width: calc(100% - var(--36px));
|
||||
}
|
||||
}
|
||||
|
||||
&:has(> .drag-handle) {
|
||||
> span.text {
|
||||
width: calc(100% - var(--36px));
|
||||
}
|
||||
}
|
||||
|
||||
&:has(> .item-button):has(> .drag-handle) {
|
||||
> span.text {
|
||||
width: calc(100% - var(--36px) - var(--18px));
|
||||
}
|
||||
}
|
||||
|
||||
> a[role="button"] {
|
||||
margin-top: var(--1px);
|
||||
margin-left: var(--2px);
|
||||
}
|
||||
}
|
||||
|
||||
.link-group-item-with-columns {
|
||||
> div > .btn-group {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
.caret {
|
||||
border-top-color: var(--gray-light);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.field, .cell {
|
||||
.checklist-label {
|
||||
color: @text-color;
|
||||
margin-bottom: 0;
|
||||
padding-left: var(--7px);
|
||||
}
|
||||
|
||||
.checklist-item-container {
|
||||
margin-bottom: var(--2px);
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
> input[type=checkbox] {
|
||||
float: left;
|
||||
}
|
||||
|
||||
> input[type=checkbox]:not(:disabled) + label {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.multi-enum-item-label-container {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
padding-bottom: var(--4px);
|
||||
|
||||
&:last-child {
|
||||
padding-bottom: var(--1px);
|
||||
}
|
||||
|
||||
.label-md {
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.field {
|
||||
> .label {
|
||||
white-space: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.filter > .form-group .field {
|
||||
.link-container {
|
||||
font-size: var(--font-size-small);
|
||||
.fa-times {
|
||||
font-size: var(--12px);
|
||||
}
|
||||
> .list-group-item {
|
||||
padding-top: var(--4px);
|
||||
padding-bottom: var(--4px);
|
||||
line-height: var(--20px);
|
||||
}
|
||||
}
|
||||
.input-group {
|
||||
input {
|
||||
font-size: var(--font-size-small);
|
||||
height: var(--input-height-small);
|
||||
min-height: var(--input-height-small);
|
||||
}
|
||||
|
||||
button.btn {
|
||||
font-size: var(--font-size-small);
|
||||
height: var(--input-height-small);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.link-container {
|
||||
> .list-group-item {
|
||||
.link-item-column {
|
||||
float: right;
|
||||
display: inline-block;
|
||||
width: 40%;
|
||||
> .selectize-control {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
> a.pull-right {
|
||||
margin-left: var(--4px);
|
||||
}
|
||||
|
||||
&,
|
||||
> .text {
|
||||
> img.avatar {
|
||||
margin-right: var(--7px);
|
||||
top: var(--2px);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.link-item-name {
|
||||
> img.avatar {
|
||||
margin-right: var(--7px);
|
||||
top: var(--2px);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.filter .field .link-container .list-group-item a[role="button"] {
|
||||
margin-top: 0;
|
||||
margin-left: var(--2px);
|
||||
}
|
||||
|
||||
.field .link-container > .list-group-item.link-with-role > a[role="button"],
|
||||
.field .link-container > .list-group-item.link-with-role > div > a[role="button"] {
|
||||
margin-top: var(--7px);
|
||||
}
|
||||
|
||||
.field .link-container > .list-group-item.link-group-item-with-columns,
|
||||
.field .link-container > .list-group-item.link-group-item-with-primary {
|
||||
> div:nth-child(1) {
|
||||
display: inline-block;
|
||||
width: calc(~"100% - 23px");
|
||||
float: left;
|
||||
input.form-control {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
> div:nth-child(2) {
|
||||
display: inline-block;
|
||||
width: var(--23px);
|
||||
float: right;
|
||||
vertical-align: top;
|
||||
}
|
||||
}
|
||||
|
||||
#main > .list-container {
|
||||
> .no-data {
|
||||
@@ -1249,14 +969,6 @@ input.global-search-input {
|
||||
}
|
||||
}
|
||||
|
||||
.filter a.remove-filter {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.filter:hover a.remove-filter {
|
||||
display: block;
|
||||
}
|
||||
|
||||
optgroup {
|
||||
font-weight: 600;
|
||||
}
|
||||
@@ -3415,7 +3127,7 @@ table.table td.cell .html-container {
|
||||
.post-container {
|
||||
.internal-mode-switcher {
|
||||
color: var(--text-muted-color);
|
||||
margin-left: var(--10px);
|
||||
margin-left: var(--14px);
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
top: var(--2px);
|
||||
@@ -4557,3 +4269,17 @@ body > .autocomplete-suggestions.text-search-suggestions {
|
||||
@import "elements/popup-notification.less";
|
||||
@import "elements/grid.less";
|
||||
@import "elements/animation.less";
|
||||
|
||||
.compact-form {
|
||||
--input-height-base: var(--input-height-small);
|
||||
--line-height-computed: var(--line-height-small);
|
||||
--line-height-base: var(--line-height-small);
|
||||
--font-size-base: var(--font-size-small);
|
||||
--padding-base-vertical: var(--padding-small-vertical);
|
||||
--padding-base-horizontal: var(--padding-small-horizontal);
|
||||
|
||||
--icon-size-base: var(--icon-size-small);
|
||||
--icon-line-height-base: var(--icon-line-height-small);
|
||||
|
||||
--btn-icon-width: var(--btn-icon-width-small);
|
||||
}
|
||||
|
||||
@@ -56,10 +56,6 @@ a.btn {
|
||||
}
|
||||
}
|
||||
|
||||
.panel-heading .btn-sm {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.input-group {
|
||||
.input-group-btn > {
|
||||
.btn {
|
||||
@@ -102,7 +98,7 @@ a.btn {
|
||||
}
|
||||
|
||||
.btn-icon {
|
||||
width: var(--36px);
|
||||
width: var(--btn-icon-width);
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
|
||||
@@ -121,7 +117,7 @@ a.btn {
|
||||
}
|
||||
|
||||
.btn-icon.btn-sm {
|
||||
width: var(--34px);
|
||||
width: var(--btn-icon-width-small);
|
||||
|
||||
.fa, .fas {
|
||||
font-size: var(--12px);
|
||||
|
||||
@@ -100,7 +100,7 @@ ul.dropdown-menu {
|
||||
line-height: var(--line-height-computed);
|
||||
|
||||
&.active {
|
||||
background-color: @gray-lighter;
|
||||
background-color: var(--dropdown-link-active-bg);
|
||||
text-decoration: none;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
@@ -124,21 +124,6 @@ input.form-control {
|
||||
}
|
||||
}
|
||||
|
||||
.link-container:not(:empty) + div,
|
||||
.link-container:not(:empty) + div > div.input-group {
|
||||
> .form-control,
|
||||
> .btn,
|
||||
> .input-group-btn > .btn {
|
||||
border-top-left-radius: 0 !important;
|
||||
border-top-right-radius: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.link-container:not(:empty) + .form-control {
|
||||
border-top-left-radius: 0 !important;
|
||||
border-top-right-radius: 0 !important;
|
||||
}
|
||||
|
||||
.input-group > .input-group-btn:first-child > select.form-control:first-child {
|
||||
border-top-left-radius: var(--border-radius);
|
||||
border-bottom-left-radius: var(--border-radius);
|
||||
@@ -510,6 +495,8 @@ input[type="radio"].form-radio {
|
||||
|
||||
.control-label {
|
||||
user-select: none;
|
||||
|
||||
font-size: var(--font-size-base);
|
||||
}
|
||||
|
||||
.form-group.hidden-cell {
|
||||
@@ -663,46 +650,316 @@ select.form-control.native-select {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
.link-container {
|
||||
a[data-action="clearLink"] {
|
||||
color: var(--gray-soft);
|
||||
&:hover {
|
||||
color: var(--btn-text-color);
|
||||
.field {
|
||||
.link-container {
|
||||
.list-group-item {
|
||||
> div {
|
||||
margin: calc(var(--6px) * -1) 0 calc(var(--6px) * -1);
|
||||
}
|
||||
|
||||
> div > div {
|
||||
margin: var(--6px) 0;
|
||||
}
|
||||
|
||||
.form-control,
|
||||
.btn {
|
||||
margin-top: var(--2px);
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
> span.text {
|
||||
width: calc(100% - var(--18px));
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
> span.drag-handle {
|
||||
display: inline-block;
|
||||
width: var(--18px);
|
||||
color: var(--text-muted-color);
|
||||
cursor: grab;
|
||||
vertical-align: top;
|
||||
|
||||
&:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
}
|
||||
|
||||
> span.item-button {
|
||||
display: inline-block;
|
||||
width: var(--18px);
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
&:has(> .item-button) {
|
||||
> span.text {
|
||||
width: calc(100% - var(--36px));
|
||||
}
|
||||
}
|
||||
|
||||
&:has(> .drag-handle) {
|
||||
> span.text {
|
||||
width: calc(100% - var(--36px));
|
||||
}
|
||||
}
|
||||
|
||||
&:has(> .item-button):has(> .drag-handle) {
|
||||
> span.text {
|
||||
width: calc(100% - var(--36px) - var(--18px));
|
||||
}
|
||||
}
|
||||
|
||||
> a[role="button"] {
|
||||
margin-top: var(--1px);
|
||||
margin-left: var(--2px);
|
||||
}
|
||||
}
|
||||
|
||||
.link-group-item-with-columns {
|
||||
> div > .btn-group {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
.caret {
|
||||
border-top-color: var(--gray-light);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> .list-group-item.link-with-role {
|
||||
> a[role="button"],
|
||||
> div > a[role="button"] {
|
||||
margin-top: var(--7px);
|
||||
}
|
||||
}
|
||||
|
||||
> .list-group-item.link-group-item-with-columns,
|
||||
> .list-group-item.link-group-item-with-primary {
|
||||
> div:nth-child(1) {
|
||||
display: inline-block;
|
||||
width: calc(~"100% - 23px");
|
||||
float: left;
|
||||
|
||||
input.form-control {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
> div:nth-child(2) {
|
||||
display: inline-block;
|
||||
width: var(--23px);
|
||||
float: right;
|
||||
vertical-align: top;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> .label {
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.list-group .list-group-item {
|
||||
background-color: var(--panel-bg);
|
||||
}
|
||||
|
||||
.list-group {
|
||||
background-color: var(--default-border-color);
|
||||
}
|
||||
}
|
||||
|
||||
.field,
|
||||
.cell {
|
||||
.checklist-label {
|
||||
color: var(--text-color);
|
||||
margin-bottom: 0;
|
||||
padding-left: var(--7px);
|
||||
}
|
||||
|
||||
.checklist-item-container {
|
||||
margin-bottom: var(--2px);
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
> input[type=checkbox] {
|
||||
float: left;
|
||||
}
|
||||
|
||||
> input[type=checkbox]:not(:disabled) + label {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.multi-enum-item-label-container {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
padding-bottom: var(--4px);
|
||||
|
||||
&:last-child {
|
||||
padding-bottom: var(--1px);
|
||||
}
|
||||
|
||||
.label-md {
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.panel-body {
|
||||
.field {
|
||||
> .link-container {
|
||||
> .list-group-item {
|
||||
background-color: var(--panel-bg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.filter {
|
||||
> .form-group .field {
|
||||
.link-container {
|
||||
font-size: var(--font-size-small);
|
||||
|
||||
.fa-times {
|
||||
font-size: var(--12px);
|
||||
}
|
||||
|
||||
> .list-group-item {
|
||||
padding-top: var(--4px);
|
||||
padding-bottom: var(--4px);
|
||||
line-height: var(--20px);
|
||||
}
|
||||
}
|
||||
|
||||
.input-group {
|
||||
input {
|
||||
font-size: var(--font-size-small);
|
||||
height: var(--input-height-small);
|
||||
min-height: var(--input-height-small);
|
||||
}
|
||||
|
||||
button.btn {
|
||||
font-size: var(--font-size-small);
|
||||
height: var(--input-height-small);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.link-container {
|
||||
.list-group-item a[role="button"] {
|
||||
margin-top: 0;
|
||||
margin-left: var(--2px);
|
||||
}
|
||||
}
|
||||
|
||||
.selectize-input {
|
||||
min-height: var(--input-height-small);
|
||||
}
|
||||
}
|
||||
|
||||
.link-container {
|
||||
> .list-group-item {
|
||||
a[role="button"] {
|
||||
color: var(--gray-soft);
|
||||
&:hover {
|
||||
color: var(--btn-text-color);
|
||||
.link-item-column {
|
||||
float: right;
|
||||
display: inline-block;
|
||||
width: 40%;
|
||||
> .selectize-control {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
> a.pull-right {
|
||||
margin-left: var(--4px);
|
||||
}
|
||||
|
||||
&,
|
||||
> .text {
|
||||
> img.avatar {
|
||||
margin-right: var(--7px);
|
||||
top: var(--2px);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.link-item-name {
|
||||
> img.avatar {
|
||||
margin-right: var(--7px);
|
||||
top: var(--2px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:not(:empty) {
|
||||
+ div,
|
||||
+ div > div.input-group {
|
||||
> .form-control,
|
||||
> .btn,
|
||||
> .input-group-btn > .btn {
|
||||
border-top-left-radius: 0 !important;
|
||||
border-top-right-radius: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
+ .form-control {
|
||||
border-top-left-radius: 0 !important;
|
||||
border-top-right-radius: 0 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.cell > .field {
|
||||
overflow-wrap: break-word;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.field {
|
||||
.add-item-container {
|
||||
a.add-item {
|
||||
color: var(--gray-soft);
|
||||
&:hover {
|
||||
color: var(--btn-text-color);
|
||||
}
|
||||
.row {
|
||||
margin-left: calc(var(--3px) * -1) !important;
|
||||
margin-right: calc(var(--3px) * -1) !important;
|
||||
|
||||
> div {
|
||||
padding-left: var(--3px) !important;
|
||||
padding-right: var(--3px) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.item-list {
|
||||
.item {
|
||||
a.remove-item {
|
||||
color: var(--gray-soft);
|
||||
&:hover {
|
||||
color: var(--btn-text-color);
|
||||
}
|
||||
.form-control,
|
||||
.btn {
|
||||
margin-bottom: var(--3px);
|
||||
}
|
||||
|
||||
.input-group .form-control,
|
||||
.input-group .btn {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.input-group {
|
||||
margin-bottom: var(--3px);
|
||||
}
|
||||
|
||||
.link-container {
|
||||
margin-bottom: 0;
|
||||
|
||||
&:not(.no-input) {
|
||||
> .list-group-item:last-child {
|
||||
border-bottom-width: 0;
|
||||
}
|
||||
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
|
||||
> .list-group-item:last-child {
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
border-bottom-width: 0;
|
||||
}
|
||||
}
|
||||
|
||||
> .list-group-item {
|
||||
.text:empty:before {
|
||||
content: "\200b";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
.fas,
|
||||
.far,
|
||||
.fa {
|
||||
font-size: var(--16px);
|
||||
line-height: var(--21px);
|
||||
font-size: var(--icon-size-base);
|
||||
line-height: var(--icon-line-height-base);
|
||||
}
|
||||
|
||||
.btn {
|
||||
@@ -11,7 +11,7 @@
|
||||
line-height: var(--line-height-computed);
|
||||
|
||||
&.fa-sm {
|
||||
line-height: var(--18px);
|
||||
line-height: var(--icon-line-height-small);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,14 +24,8 @@
|
||||
.small .fas,
|
||||
.fas.small,
|
||||
.far.small {
|
||||
font-size: var(--12px);
|
||||
line-height: var(--18px);
|
||||
}
|
||||
|
||||
.btn:not(.btn-sm) {
|
||||
> .fas.fa-ellipsis-h {
|
||||
//line-height: var(--23px);
|
||||
}
|
||||
font-size: var(--icon-size-small);
|
||||
line-height: var(--icon-line-height-small);
|
||||
}
|
||||
|
||||
.btn:not(.btn-sm),
|
||||
|
||||
@@ -271,7 +271,7 @@
|
||||
|
||||
@media screen and (min-width: @screen-md-min) {
|
||||
.modal-dialog {
|
||||
width: ~"min(var(--900px), 90vw)";
|
||||
width: ~"min(calc(var(--900px) + var(--30px)), 90vw)";
|
||||
}
|
||||
|
||||
.dialog-confirm > .modal-dialog,
|
||||
@@ -348,8 +348,12 @@
|
||||
}
|
||||
|
||||
|
||||
.modal.dialog-record {
|
||||
.modal-body {
|
||||
scrollbar-gutter: stable;
|
||||
.modal {
|
||||
&.dialog-record,
|
||||
&:has(> .modal-dialog > .modal-content > .modal-body > .record.no-side-margin),
|
||||
&:has(> .modal-dialog > .modal-content > .modal-body > .record-container.no-side-margin) {
|
||||
.modal-body {
|
||||
scrollbar-gutter: stable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -618,6 +618,10 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
.panel-heading .btn-sm {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.panel.highlighted {
|
||||
outline: var(--2px) solid var(--brand-info);
|
||||
outline-offset: var(--minus-1px);
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
}
|
||||
|
||||
&.record-grid-small {
|
||||
grid-template-columns: minmax(auto, 60%) minmax(auto, 40%);
|
||||
grid-template-columns: minmax(auto, 61%) minmax(auto, 39%);
|
||||
}
|
||||
|
||||
max-width: var(--record-grid-max-width);
|
||||
@@ -35,6 +35,38 @@
|
||||
.record .record-grid {
|
||||
grid-column-gap: var(--padding-base-horizontal);
|
||||
}
|
||||
|
||||
@media screen and (min-width: @screen-sm-min) {
|
||||
.record,
|
||||
.record-container,
|
||||
.edit-container {
|
||||
&.no-side-margin {
|
||||
> div {
|
||||
> .record-grid-wide {
|
||||
margin-right: var(--panel-padding);
|
||||
|
||||
> .left {
|
||||
> .middle {
|
||||
> .panel {
|
||||
|
||||
&:not(.middle):not(.last),
|
||||
&.first {
|
||||
border-top-right-radius: var(--panel-border-radius);
|
||||
}
|
||||
|
||||
&:not(.middle):not(.first),
|
||||
&.last {
|
||||
border-bottom-right-radius: var(--panel-border-radius);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: @screen-sm-max) {
|
||||
|
||||
@@ -152,7 +152,7 @@ label {
|
||||
|
||||
.label-md {
|
||||
font-weight: normal;
|
||||
font-size: 100%;
|
||||
font-size: var(--font-size-base);
|
||||
padding: var(--1px) var(--7px) var(--2px);
|
||||
top: 0;
|
||||
line-height: 1.8;
|
||||
@@ -270,6 +270,13 @@ a.text-default {
|
||||
}
|
||||
}
|
||||
|
||||
a.no-underline {
|
||||
&:hover,
|
||||
&:focus {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
.nowrap {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@@ -481,6 +481,7 @@
|
||||
--dropdown-border: @dropdown-border-value;
|
||||
--dropdown-divider-bg: @dropdown-divider-bg-value;
|
||||
--dropdown-box-shadow: @dropdown-box-shadow-value;
|
||||
--dropdown-link-active-bg: @dropdown-link-active-bg-value;
|
||||
|
||||
--calendar-today-bg: @calendar-today-bg-value;
|
||||
--calendar-border: @calendar-border-value;
|
||||
@@ -510,4 +511,15 @@
|
||||
--top-bar-box-shadow: @top-bar-box-shadow-value;
|
||||
|
||||
--vertical-gap: @vertical-gap-value;
|
||||
|
||||
//
|
||||
|
||||
--icon-size-base: var(--16px);
|
||||
--icon-line-height-base: var(--21px);
|
||||
|
||||
--icon-size-small: var(--12px);
|
||||
--icon-line-height-small: var(--18px);
|
||||
|
||||
--btn-icon-width: var(--36px);
|
||||
--btn-icon-width-small: var(--32px);
|
||||
}
|
||||
|
||||
@@ -208,6 +208,7 @@
|
||||
@dropdown-border-width-value: var(--1px);
|
||||
@dropdown-divider-bg-value: #e5e5e5;
|
||||
@dropdown-box-shadow-value: 0 4px 6px rgba(0, 0, 0, 0.11);
|
||||
@dropdown-link-active-bg-value: @gray-lighter-value;
|
||||
|
||||
@login-panel-heading-bg-value: @panel-bg-value;
|
||||
|
||||
|
||||
@@ -123,6 +123,7 @@
|
||||
@dropdown-divider-bg-value: @default-border-color-value;
|
||||
@dropdown-border-value: transparent;
|
||||
@dropdown-border-width-value: 0;
|
||||
@dropdown-link-active-bg-value: #4D4950C7;
|
||||
|
||||
@select-item-bg-value: #1e253054;
|
||||
@select-item-border-value: @btn-default-border-value;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
@body-bg-value: #d3dee3;
|
||||
@body-bg-value: #e1e9ed;
|
||||
@white-color-value: #FFF;
|
||||
@panel-bg-value: @white-color-value;
|
||||
|
||||
@link-color-value: #5b8fc8;
|
||||
|
||||
@navbar-inverse-bg-value: @body-bg-value;
|
||||
@navbar-inverse-link-active-bg-value: #bbc6cb;
|
||||
@navbar-inverse-link-hover-bg-value: #c8d4d9;
|
||||
@navbar-inverse-bg-value: #edf1f3;
|
||||
@navbar-inverse-link-active-bg-value: #d9e0e3;
|
||||
@navbar-inverse-link-hover-bg-value: #e5e9eb;
|
||||
@navbar-inverse-color-value: #8d8f93;
|
||||
|
||||
@navbar-box-shadow-value: @default-box-shadow-value;
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "espocrm",
|
||||
"version": "9.2.2",
|
||||
"version": "9.2.4",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "espocrm",
|
||||
"version": "9.2.2",
|
||||
"version": "9.2.4",
|
||||
"hasInstallScript": true,
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "espocrm",
|
||||
"version": "9.2.2",
|
||||
"version": "9.2.4",
|
||||
"description": "Open-source CRM.",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -993,6 +993,26 @@
|
||||
},
|
||||
"description": "Parameters available in the Entity Manager tool when editing the field. Specify an empty array to disable all parameters."
|
||||
},
|
||||
"fieldManagerAdditionalParamList": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"allOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "A parameter name."
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"$ref": "entityDefs.json#/definitions/fieldDefs"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "Additional field parameters available in the Entity Manager."
|
||||
},
|
||||
"layoutAvailabilityList": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -1259,6 +1279,10 @@
|
||||
"type": "boolean",
|
||||
"description": "Linking and unlinking will be logged in the Stream. Available for hasMany."
|
||||
},
|
||||
"auditView": {
|
||||
"type": "string",
|
||||
"description": "A view used for audit. If not specified, the ordinary view is used. As of v9.2.3."
|
||||
},
|
||||
"readOnly": {
|
||||
"type": "boolean",
|
||||
"description": "Read-only links cannot be edited via link and unlink requests. But they can be edited via link and link-multiple fields."
|
||||
|
||||
Reference in New Issue
Block a user