options ref

This commit is contained in:
Yuri Kuznetsov
2023-04-11 12:41:18 +03:00
parent 7365007511
commit 66ecf7794e
17 changed files with 268 additions and 37 deletions

View File

@@ -128,6 +128,14 @@ class ArrayType
/** @var ?string $path */
$path = $fieldDefs->getParam('optionsPath');
/** @var ?string $path */
$ref = $fieldDefs->getParam('optionsReference');
if (!$path && $ref && str_contains($ref, '.')) {
[$refEntityType, $refField] = explode('.', $ref);
$path = "entityDefs.{$refEntityType}.fields.{$refField}.options";
}
/** @var string[]|null|false $optionList */
$optionList = $path ?

View File

@@ -37,7 +37,6 @@ use Espo\ORM\Entity;
class EnumType
{
private Metadata $metadata;
private Defs $defs;
private const DEFAULT_MAX_LENGTH = 255;
@@ -65,6 +64,14 @@ class EnumType
/** @var ?string $path */
$path = $fieldDefs->getParam('optionsPath');
/** @var ?string $path */
$ref = $fieldDefs->getParam('optionsReference');
if (!$path && $ref && str_contains($ref, '.')) {
[$refEntityType, $refField] = explode('.', $ref);
$path = "entityDefs.{$refEntityType}.fields.{$refField}.options";
}
/** @var string[]|null|false $optionList */
$optionList = $path ?

View File

@@ -1,13 +1,5 @@
{
"aclDependencies": {
"Lead.options.source": {
"scope": "Opportunity",
"field": "leadSource"
},
"Account.options.industry": {
"scope": "Lead",
"field": "industry"
},
"Meeting": {
"anyScopeList": ["Call"]
}

View File

@@ -1,14 +1,5 @@
{
"aclDependencies": {
"entityDefs.Lead.fields.source.options": {
"scope": "Opportunity",
"field": "leadSource"
},
"entityDefs.Account.fields.industry.options": {
"scope": "Lead",
"field": "industry"
}
},
"aclDependencies": {},
"frontendHiddenPathList": [
"__APPEND__",
["app", "calendar", "additionalAttributeList"]

View File

@@ -66,8 +66,7 @@
"type": "enum",
"view": "crm:views/lead/fields/industry",
"customizationOptionsDisabled": true,
"optionsPath": "entityDefs.Account.fields.industry.options",
"translation": "Account.options.industry",
"optionsReference": "Account.industry",
"default": "",
"isSorted": true
},

View File

@@ -201,8 +201,7 @@
"type": "enum",
"view": "crm:views/opportunity/fields/lead-source",
"customizationOptionsDisabled": true,
"optionsPath": "entityDefs.Lead.fields.source.options",
"translation": "Lead.options.source"
"optionsReference": "Lead.source"
},
"closeDate": {
"type": "date",

View File

@@ -162,6 +162,7 @@
"default": "Default",
"maxLength": "Max Length",
"options": "Options",
"optionsReference": "Options Reference",
"after": "After (field)",
"before": "Before (field)",
"link": "Link",

View File

@@ -80,6 +80,7 @@
}
},
"tooltips": {
"optionsReference": "Re-use options from another field.",
"currencyDecimal": "Use the Decimal DB type. In the app, values will be represented as strings. Check this parameter if precision is required.",
"cutHeight": "A text higher then a specified value will be cut with a 'show more' button displayed.",
"urlStrip": "Strip a protocol and a trailing slash.",

View File

@@ -11,6 +11,12 @@
"view": "views/admin/field-manager/fields/options",
"tooltip": "optionsArray"
},
{
"name": "optionsReference",
"type": "varchar",
"view": "views/admin/field-manager/fields/options-reference",
"tooltip": true
},
{
"name": "translation",
"type": "varchar",

View File

@@ -13,6 +13,12 @@
"required": true,
"tooltip": true
},
{
"name": "optionsReference",
"type": "varchar",
"view": "views/admin/field-manager/fields/options-reference",
"tooltip": true
},
{
"name": "isSorted",
"type": "bool"

View File

@@ -16,6 +16,12 @@
"type": "enum",
"view": "views/admin/field-manager/fields/options/default"
},
{
"name": "optionsReference",
"type": "varchar",
"view": "views/admin/field-manager/fields/options-reference",
"tooltip": true
},
{
"name": "isSorted",
"type": "bool"

View File

@@ -11,6 +11,12 @@
"view": "views/admin/field-manager/fields/options-with-style",
"tooltip": true
},
{
"name": "optionsReference",
"type": "varchar",
"view": "views/admin/field-manager/fields/options-reference",
"tooltip": true
},
{
"name": "isSorted",
"type": "bool"

View File

@@ -32,11 +32,20 @@ namespace Espo\Tools\App\Language;
use Espo\Core\Utils\Config;
use Espo\Core\Utils\DataCache;
use Espo\Core\Utils\Metadata;
use Espo\ORM\Defs;
class AclDependencyProvider
{
private const CACHE_KEY = 'languageAclDependency';
/** @var string[] */
private array $enumFieldTypeList = [
'enum',
'multiEnum',
'array',
'checklist',
];
/** @var ?AclDependencyItem[] */
private ?array $data = null;
private bool $useCache;
@@ -44,7 +53,8 @@ class AclDependencyProvider
public function __construct(
private DataCache $dataCache,
private Metadata $metadata,
Config $config
Config $config,
private Defs $ormDefs
) {
$this->useCache = $config->get('useCache');
}
@@ -96,6 +106,35 @@ class AclDependencyProvider
];
}
foreach ($this->ormDefs->getEntityList() as $entityDefs) {
if (!$this->metadata->get(['scopes', $entityDefs->getName(), 'object'])) {
continue;
}
foreach ($entityDefs->getFieldList() as $fieldDefs) {
if (!in_array($fieldDefs->getType(), $this->enumFieldTypeList)) {
continue;
}
$optionsReference = $fieldDefs->getParam('optionsReference');
if (!$optionsReference || !str_contains($optionsReference, '.')) {
continue;
}
[$refEntityType, $refField] = explode('.', $optionsReference);
$target = "{$refEntityType}.options.{$refField}";
$data[] = [
'target' => $target,
'anyScopeList' => null,
'scope' => $entityDefs->getName(),
'field' => $fieldDefs->getName(),
];
}
}
if ($this->useCache) {
$this->dataCache->store(self::CACHE_KEY, $data);
}

View File

@@ -32,11 +32,20 @@ namespace Espo\Tools\App\Metadata;
use Espo\Core\Utils\Config;
use Espo\Core\Utils\DataCache;
use Espo\Core\Utils\Metadata;
use Espo\ORM\Defs;
class AclDependencyProvider
{
private const CACHE_KEY = 'metadataAclDependency';
/** @var string[] */
private array $enumFieldTypeList = [
'enum',
'multiEnum',
'array',
'checklist',
];
/** @var ?AclDependencyItem[] */
private ?array $data = null;
private bool $useCache;
@@ -44,7 +53,8 @@ class AclDependencyProvider
public function __construct(
private DataCache $dataCache,
private Metadata $metadata,
Config $config
Config $config,
private Defs $ormDefs
) {
$this->useCache = $config->get('useCache');
}
@@ -98,6 +108,41 @@ class AclDependencyProvider
];
}
foreach ($this->ormDefs->getEntityList() as $entityDefs) {
if (!$this->metadata->get(['scopes', $entityDefs->getName(), 'object'])) {
continue;
}
foreach ($entityDefs->getFieldList() as $fieldDefs) {
if (!in_array($fieldDefs->getType(), $this->enumFieldTypeList)) {
continue;
}
$optionsPath = $fieldDefs->getParam('optionsPath');
$optionsReference = $fieldDefs->getParam('optionsReference');
if (
!$optionsPath &&
$optionsReference &&
str_contains($optionsReference, '.')
) {
[$refEntityType, $refField] = explode('.', $optionsReference);
$optionsPath = "entityDefs.{$refEntityType}.fields.{$refField}.options";
}
if (!$optionsPath) {
continue;
}
$data[] = [
'target' => $optionsPath,
'scope' => $entityDefs->getName(),
'field' => $fieldDefs->getName(),
];
}
}
if ($this->useCache) {
$this->dataCache->store(self::CACHE_KEY, $data);
}

View File

@@ -0,0 +1,89 @@
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2023 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://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.
************************************************************************/
define('views/admin/field-manager/fields/options-reference', ['views/fields/enum'], function (Dep) {
return Dep.extend({
enumFieldTypeList: [
'enum',
'multiEnum',
'array',
'checklist',
'varchar',
],
setupOptions: function () {
this.params.options = [''];
let entityTypeList = Object.keys(this.getMetadata().get(['entityDefs']))
.filter(item => this.getMetadata().get(['scopes', item, 'object']))
.sort((s1, s2) => {
return this.getLanguage().translate(s1, 'scopesName')
.localeCompare(this.getLanguage().translate(s2, 'scopesName'));
});
this.translatedOptions = {};
entityTypeList.forEach(entityType => {
let fieldList =
Object.keys(this.getMetadata().get(['entityDefs', entityType, 'fields']) || [])
.filter(item => entityType !== this.model.scope || item !== this.model.get('name'))
.sort((s1, s2) => {
return this.getLanguage().translate(s1, 'fields', entityType)
.localeCompare(this.getLanguage().translate(s2, 'fields', entityType));
});
fieldList.forEach(field => {
let {type, options, optionsPath, optionsReference} =
this.getMetadata().get(['entityDefs', entityType, 'fields', field]) || {};
if (!this.enumFieldTypeList.includes(type)) {
return;
}
if (optionsPath || optionsReference) {
return;
}
if (!options) {
return;
}
let value = entityType + '.' + field;
this.params.options.push(value);
this.translatedOptions[value] =
this.translate(entityType, 'scopeName') + ' · ' +
this.translate(field, 'fields', entityType);
});
});
},
});
});

View File

@@ -138,10 +138,18 @@ function (Dep, RegExpPattern, /** module:ui/multi-select*/MultiSelect) {
this.selected = [];
}
if (this.params.optionsPath) {
this.params.options = Espo.Utils.clone(
this.getMetadata().get(this.params.optionsPath) || []
);
let optionsPath = this.params.optionsPath;
/** @type {?string} */
let optionsReference = this.params.optionsReference;
if (!optionsPath && optionsReference) {
let [refEntityType, refField] = optionsReference.split('.');
optionsPath = `entityDefs.${refEntityType}.fields.${refField}.options`;
}
if (optionsPath) {
this.params.options = Espo.Utils.clone(this.getMetadata().get(optionsPath)) || [];
}
this.styleMap = this.params.style || {};
@@ -214,8 +222,18 @@ function (Dep, RegExpPattern, /** module:ui/multi-select*/MultiSelect) {
setupTranslation: function () {
let t = {};
if (this.params.translation) {
let arr = this.params.translation.split('.');
let translation = this.params.translation;
/** @type {?string} */
let optionsReference = this.params.optionsReference;
if (!translation && optionsReference) {
let [refEntityType, refField] = optionsReference.split('.');
translation = `${refEntityType}.options.${refField}`;
}
if (translation) {
let arr = translation.split('.');
let pointer = this.getLanguage().data;

View File

@@ -109,10 +109,18 @@ function (Dep, /** module:ui/multi-select*/MultiSelect, /** module:ui/select*/Se
}
}
if (this.params.optionsPath) {
this.params.options = Espo.Utils.clone(
this.getMetadata().get(this.params.optionsPath) || []
);
let optionsPath = this.params.optionsPath;
/** @type {?string} */
let optionsReference = this.params.optionsReference;
if (!optionsPath && optionsReference) {
let [refEntityType, refField] = optionsReference.split('.');
optionsPath = `entityDefs.${refEntityType}.fields.${refField}.options`;
}
if (optionsPath) {
this.params.options = Espo.Utils.clone(this.getMetadata().get(optionsPath)) || [];
}
this.styleMap = this.params.style || this.model.getFieldParam(this.name, 'style') || {};
@@ -153,13 +161,23 @@ function (Dep, /** module:ui/multi-select*/MultiSelect, /** module:ui/select*/Se
},
setupTranslation: function () {
if (!this.params.translation) {
let translation = this.params.translation;
/** @type {?string} */
let optionsReference = this.params.optionsReference;
if (!translation && optionsReference) {
let [refEntityType, refField] = optionsReference.split('.');
translation = `${refEntityType}.options.${refField}`;
}
if (!translation) {
return;
}
let translationObj;
let arr = this.params.translation.split('.');
let arr = translation.split('.');
let pointer = this.getLanguage().data;
arr.forEach(key => {