diff --git a/.idea/jsonSchemas.xml b/.idea/jsonSchemas.xml
index 859c5652b2..20c366d73d 100644
--- a/.idea/jsonSchemas.xml
+++ b/.idea/jsonSchemas.xml
@@ -1386,6 +1386,25 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 1db639ab7d..6aac458309 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -82,6 +82,12 @@
],
"url": "./schema/metadata/integrations.json"
},
+ {
+ "fileMatch": [
+ "*/metadata/logicDefs/*.json"
+ ],
+ "url": "./schema/metadata/logicDefs.json"
+ },
{
"fileMatch": [
"*/metadata/notificationDefs/*.json"
diff --git a/application/Espo/Core/Upgrades/Migrations/V9_1/AfterUpgrade.php b/application/Espo/Core/Upgrades/Migrations/V9_1/AfterUpgrade.php
index 3ac76c0cb9..87a661e7ac 100644
--- a/application/Espo/Core/Upgrades/Migrations/V9_1/AfterUpgrade.php
+++ b/application/Espo/Core/Upgrades/Migrations/V9_1/AfterUpgrade.php
@@ -31,19 +31,24 @@ namespace Espo\Core\Upgrades\Migrations\V9_1;
use Espo\Core\ORM\Repository\Option\SaveOption;
use Espo\Core\Upgrades\Migration\Script;
+use Espo\Core\Utils\Metadata;
+use Espo\Core\Utils\ObjectUtil;
use Espo\Modules\Crm\Entities\KnowledgeBaseArticle;
use Espo\ORM\EntityManager;
use Espo\Tools\Email\Util;
+use stdClass;
class AfterUpgrade implements Script
{
public function __construct(
private EntityManager $entityManager,
+ private Metadata $metadata,
) {}
public function run(): void
{
$this->processKbArticles();
+ $this->processDynamicLogicMetadata();
}
private function processKbArticles(): void
@@ -71,4 +76,32 @@ class AfterUpgrade implements Script
$this->entityManager->saveEntity($article, [SaveOption::SKIP_HOOKS => true]);
}
}
+
+ private function processDynamicLogicMetadata(): void
+ {
+ /** @var string[] $scopes */
+ $scopes = array_keys($this->metadata->get('clientDefs', []));
+
+ foreach ($scopes as $scope) {
+ $customClientDefs = $this->metadata->getCustom('clientDefs', $scope);
+
+ if (!$customClientDefs instanceof stdClass) {
+ continue;
+ }
+
+ if (
+ !property_exists($customClientDefs, 'dynamicLogic') ||
+ !$customClientDefs->dynamicLogic instanceof stdClass
+ ) {
+ continue;
+ }
+
+ $this->metadata->saveCustom('logicDefs', $scope, $customClientDefs->dynamicLogic);
+
+ $customClientDefs = ObjectUtil::clone($customClientDefs);
+ unset($customClientDefs->dynamicLogic);
+
+ $this->metadata->saveCustom('clientDefs', $scope, $customClientDefs);
+ }
+ }
}
diff --git a/application/Espo/Core/Utils/Metadata/AdditionalBuilder/LogicDefsBc.php b/application/Espo/Core/Utils/Metadata/AdditionalBuilder/LogicDefsBc.php
new file mode 100644
index 0000000000..ff8d9b0ac9
--- /dev/null
+++ b/application/Espo/Core/Utils/Metadata/AdditionalBuilder/LogicDefsBc.php
@@ -0,0 +1,162 @@
+.
+ *
+ * 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\Metadata\AdditionalBuilder;
+
+use Espo\Core\Utils\Metadata\AdditionalBuilder;
+use Espo\Core\Utils\ObjectUtil;
+use stdClass;
+
+/**
+ * Establishes backward compatibility of clientDefs > {scope} > dynamicLogic.
+ * The dynamic logic is NOT supposed to be set in custom clientDefs as of v9.1.
+ * The custom dynamic logic is supposed to be moved to logicDefs by an upgrade script.
+ * But extensions can have a dynamic logic defined in clientDefs as they may be supposed
+ * to be compatible with older Espo versions.
+ *
+ * @noinspection PhpUnused
+ */
+class LogicDefsBc implements AdditionalBuilder
+{
+ public function build(stdClass $data): void
+ {
+ if (!isset($data->clientDefs)) {
+ return;
+ }
+
+ /** @var array $clientDefs */
+ $clientDefs = get_object_vars($data->clientDefs);
+
+ foreach ($clientDefs as $scope => $defs) {
+ $this->processScope($scope, $data);
+ }
+ }
+
+ private function processScope(string $scope, stdClass $data): void
+ {
+ if (!isset($data->clientDefs->$scope)) {
+ return;
+ }
+
+ /** @var stdClass $clientDefs */
+ $clientDefs = $data->clientDefs->$scope;
+
+ if (!isset($clientDefs->dynamicLogic)) {
+ return;
+ }
+
+ /** @var stdClass $dynamicLogic */
+ $dynamicLogic = $clientDefs->dynamicLogic;
+
+ $keys = [
+ 'fields',
+ 'panels',
+ ];
+
+ $subKeys = [
+ 'visible',
+ 'required',
+ 'readOnly',
+ 'invalid',
+ ];
+
+ $data->logicDefs ??= (object) [];
+ $data->logicDefs->$scope ??= (object) [];
+
+ /** @var stdClass $logicDefs */
+ $logicDefs = $data->logicDefs->$scope;
+
+ $customFile = "custom/Espo/Custom/Resources/metadata/logicDefs/$scope.json";
+
+ $customLogicDefs = file_exists($customFile) ?
+ json_decode(file_get_contents($customFile) ?: '') :
+ null;
+
+ if (!$customLogicDefs instanceof stdClass) {
+ $customLogicDefs = (object) [];
+ }
+
+ foreach ($keys as $key) {
+ if (!isset($dynamicLogic->$key)) {
+ continue;
+ }
+
+ /** @var array $defs */
+ $defs = get_object_vars($dynamicLogic->$key);
+
+ foreach ($defs as $name => $subDefs) {
+
+ foreach ($subKeys as $subKey) {
+ if (!property_exists($subDefs, $subKey)) {
+ continue;
+ }
+
+ if (
+ isset($customLogicDefs->$key->$name) &&
+ property_exists($customLogicDefs->$key->$name, $subKey)
+ ) {
+ // Overridden in custom.
+ continue;
+ }
+
+ /** @var stdClass|null $item */
+ $item = $subDefs->$subKey;
+
+ $logicDefs->$key ??= (object) [];
+ $logicDefs->$key->$name ??= (object) [];
+
+ $logicDefs->$key->$name->$subKey = $item !== null ?
+ ObjectUtil::clone($item) :
+ null;
+ }
+ }
+ }
+
+ if (isset($dynamicLogic->options)) {
+ /** @var array $defs */
+ $defs = get_object_vars($dynamicLogic->options);
+
+ foreach ($defs as $name => $subDefs) {
+ if (
+ isset($customLogicDefs->options) &&
+ property_exists($customLogicDefs->options, $name)
+ ) {
+ // Overridden in custom.
+ continue;
+ }
+
+ $logicDefs->options ??= (object) [];
+
+ $logicDefs->options->$name = $subDefs !== null ?
+ array_map(fn ($it) => ObjectUtil::clone($it), $subDefs) :
+ null;
+ }
+ }
+ }
+}
diff --git a/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Campaign.json b/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Campaign.json
index 6de160245f..074a5c7a4d 100644
--- a/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Campaign.json
+++ b/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Campaign.json
@@ -80,166 +80,6 @@
"filterList": [
"active"
],
- "dynamicLogic": {
- "fields": {
- "targetLists": {
- "visible": {
- "conditionGroup": [
- {
- "type": "or",
- "value": [
- {
- "type": "equals",
- "attribute": "type",
- "value": "Email"
- },
- {
- "type": "equals",
- "attribute": "type",
- "value": "Newsletter"
- },
- {
- "type": "equals",
- "attribute": "type",
- "value": "Informational Email"
- },
- {
- "type": "equals",
- "attribute": "type",
- "value": "Mail"
- }
- ]
- }
- ]
- }
- },
- "excludingTargetLists": {
- "visible": {
- "conditionGroup": [
- {
- "type": "or",
- "value": [
- {
- "type": "equals",
- "attribute": "type",
- "value": "Email"
- },
- {
- "type": "equals",
- "attribute": "type",
- "value": "Newsletter"
- },
- {
- "type": "equals",
- "attribute": "type",
- "value": "Informational Email"
- },
- {
- "type": "equals",
- "attribute": "type",
- "value": "Mail"
- }
- ]
- }
- ]
- }
- },
- "contactsTemplate": {
- "visible": {
- "conditionGroup": [
- {
- "type": "equals",
- "attribute": "type",
- "value": "Mail"
- }
- ]
- }
- },
- "leadsTemplate": {
- "visible": {
- "conditionGroup": [
- {
- "type": "equals",
- "attribute": "type",
- "value": "Mail"
- }
- ]
- }
- },
- "accountsTemplate": {
- "visible": {
- "conditionGroup": [
- {
- "type": "equals",
- "attribute": "type",
- "value": "Mail"
- }
- ]
- }
- },
- "usersTemplate": {
- "visible": {
- "conditionGroup": [
- {
- "type": "equals",
- "attribute": "type",
- "value": "Mail"
- }
- ]
- }
- },
- "mailMergeOnlyWithAddress": {
- "visible": {
- "conditionGroup": [
- {
- "type": "equals",
- "attribute": "type",
- "value": "Mail"
- }
- ]
- }
- }
- },
- "panels": {
- "massEmails": {
- "visible": {
- "conditionGroup": [
- {
- "type": "in",
- "attribute": "type",
- "value": [
- "Email",
- "Newsletter",
- "Informational Email"
- ]
- }
- ]
- }
- },
- "trackingUrls": {
- "visible": {
- "conditionGroup": [
- {
- "type": "in",
- "attribute": "type",
- "value": ["Email", "Newsletter"]
- }
- ]
- }
- },
- "mailMerge": {
- "visible": {
- "conditionGroup": [
- {
- "type": "in",
- "attribute": "type",
- "value": ["Mail"]
- }
- ]
- }
- }
- }
- },
"boolFilterList": ["onlyMy"],
"iconClass": "fas fa-chart-line"
}
diff --git a/application/Espo/Modules/Crm/Resources/metadata/clientDefs/CampaignTrackingUrl.json b/application/Espo/Modules/Crm/Resources/metadata/clientDefs/CampaignTrackingUrl.json
index 0be9c76f69..f72ce9f23d 100644
--- a/application/Espo/Modules/Crm/Resources/metadata/clientDefs/CampaignTrackingUrl.json
+++ b/application/Espo/Modules/Crm/Resources/metadata/clientDefs/CampaignTrackingUrl.json
@@ -8,49 +8,5 @@
"defaultSidePanel": {
"edit": false,
"editSmall": false
- },
- "dynamicLogic": {
- "fields": {
- "url": {
- "visible": {
- "conditionGroup": [
- {
- "type": "equals",
- "attribute": "action",
- "value": "Redirect"
- }
- ]
- },
- "required": {
- "conditionGroup": [
- {
- "type": "equals",
- "attribute": "action",
- "value": "Redirect"
- }
- ]
- }
- },
- "message": {
- "visible": {
- "conditionGroup": [
- {
- "type": "equals",
- "attribute": "action",
- "value": "Show Message"
- }
- ]
- },
- "required": {
- "conditionGroup": [
- {
- "type": "equals",
- "attribute": "action",
- "value": "Show Message"
- }
- ]
- }
- }
- }
}
}
diff --git a/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Case.json b/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Case.json
index e8292c966b..4ddbb3bc2c 100644
--- a/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Case.json
+++ b/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Case.json
@@ -104,20 +104,6 @@
"filter": "open"
},
"allowInternalNotes": true,
- "dynamicLogic": {
- "fields": {
- "number": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isNotEmpty",
- "attribute": "id"
- }
- ]
- }
- }
- }
- },
"additionalLayouts": {
"detailPortal": {
"type": "detail"
diff --git a/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Contact.json b/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Contact.json
index 8550990671..72f0bdf762 100644
--- a/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Contact.json
+++ b/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Contact.json
@@ -98,33 +98,6 @@
"filterList": [
"portalUsers"
],
- "dynamicLogic": {
- "fields": {
- "title": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isNotEmpty",
- "attribute": "accountId"
- }
- ]
- }
- },
- "portalUser": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isNotEmpty",
- "attribute": "portalUserId",
- "data": {
- "field": "portalUser"
- }
- }
- ]
- }
- }
- }
- },
"color": "#a4c5e0",
"iconClass": "fas fa-id-badge"
}
diff --git a/application/Espo/Modules/Crm/Resources/metadata/clientDefs/MassEmail.json b/application/Espo/Modules/Crm/Resources/metadata/clientDefs/MassEmail.json
index c81f729eaa..e9ea244244 100644
--- a/application/Espo/Modules/Crm/Resources/metadata/clientDefs/MassEmail.json
+++ b/application/Espo/Modules/Crm/Resources/metadata/clientDefs/MassEmail.json
@@ -28,65 +28,6 @@
]
}
},
- "dynamicLogic": {
- "fields": {
- "status": {
- "readOnly": {
- "conditionGroup": [
- {
- "type": "and",
- "value": [
- {
- "type": "or",
- "value": [
- {
- "type": "equals",
- "attribute": "status",
- "value": "Complete"
- },
- {
- "type": "equals",
- "attribute": "status",
- "value": "In Process"
- },
- {
- "type": "equals",
- "attribute": "status",
- "value": "Failed"
- }
- ]
- },
- {
- "type": "isNotEmpty",
- "attribute": "id"
- }
- ]
- }
- ]
- }
- }
- },
- "options": {
- "status": [
- {
- "optionList": [
- "Draft",
- "Pending"
- ],
- "conditionGroup": [
- {
- "type": "in",
- "attribute": "status",
- "value": [
- "Draft",
- "Pending"
- ]
- }
- ]
- }
- ]
- }
- },
"filterList": [
{
"name":"actual"
diff --git a/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Opportunity.json b/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Opportunity.json
index 94c3c97e6f..dc8bd23e1c 100644
--- a/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Opportunity.json
+++ b/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Opportunity.json
@@ -99,21 +99,6 @@
"selectHandler": "handlers/select-related/same-account-many"
}
},
- "dynamicLogic": {
- "fields": {
- "lastStage": {
- "visible": {
- "conditionGroup": [
- {
- "type": "equals",
- "attribute": "stage",
- "value": "Closed Lost"
- }
- ]
- }
- }
- }
- },
"color": "#9fc77e",
"iconClass": "fas fa-dollar-sign"
}
diff --git a/application/Espo/Modules/Crm/Resources/metadata/clientDefs/TargetList.json b/application/Espo/Modules/Crm/Resources/metadata/clientDefs/TargetList.json
index 201da6d7ed..f818da6294 100644
--- a/application/Espo/Modules/Crm/Resources/metadata/clientDefs/TargetList.json
+++ b/application/Espo/Modules/Crm/Resources/metadata/clientDefs/TargetList.json
@@ -88,29 +88,5 @@
"massSelect": true
}
},
- "dynamicLogic": {
- "fields": {
- "entryCount": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isNotEmpty",
- "attribute": "id"
- }
- ]
- }
- },
- "optedOutCount": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isNotEmpty",
- "attribute": "id"
- }
- ]
- }
- }
- }
- },
"iconClass":"fas fa-crosshairs"
}
diff --git a/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Task.json b/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Task.json
index e08d486664..86da441f15 100644
--- a/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Task.json
+++ b/application/Espo/Modules/Crm/Resources/metadata/clientDefs/Task.json
@@ -46,21 +46,6 @@
"checkVisibilityFunction": "isCompleteAvailable"
}
],
- "dynamicLogic": {
- "fields": {
- "dateCompleted": {
- "visible": {
- "conditionGroup": [
- {
- "type": "equals",
- "attribute": "status",
- "value": "Completed"
- }
- ]
- }
- }
- }
- },
"filterList": [
"actual",
{
diff --git a/application/Espo/Modules/Crm/Resources/metadata/logicDefs/Campaign.json b/application/Espo/Modules/Crm/Resources/metadata/logicDefs/Campaign.json
new file mode 100644
index 0000000000..acb41d069e
--- /dev/null
+++ b/application/Espo/Modules/Crm/Resources/metadata/logicDefs/Campaign.json
@@ -0,0 +1,160 @@
+{
+ "fields": {
+ "targetLists": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "or",
+ "value": [
+ {
+ "type": "equals",
+ "attribute": "type",
+ "value": "Email"
+ },
+ {
+ "type": "equals",
+ "attribute": "type",
+ "value": "Newsletter"
+ },
+ {
+ "type": "equals",
+ "attribute": "type",
+ "value": "Informational Email"
+ },
+ {
+ "type": "equals",
+ "attribute": "type",
+ "value": "Mail"
+ }
+ ]
+ }
+ ]
+ }
+ },
+ "excludingTargetLists": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "or",
+ "value": [
+ {
+ "type": "equals",
+ "attribute": "type",
+ "value": "Email"
+ },
+ {
+ "type": "equals",
+ "attribute": "type",
+ "value": "Newsletter"
+ },
+ {
+ "type": "equals",
+ "attribute": "type",
+ "value": "Informational Email"
+ },
+ {
+ "type": "equals",
+ "attribute": "type",
+ "value": "Mail"
+ }
+ ]
+ }
+ ]
+ }
+ },
+ "contactsTemplate": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "equals",
+ "attribute": "type",
+ "value": "Mail"
+ }
+ ]
+ }
+ },
+ "leadsTemplate": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "equals",
+ "attribute": "type",
+ "value": "Mail"
+ }
+ ]
+ }
+ },
+ "accountsTemplate": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "equals",
+ "attribute": "type",
+ "value": "Mail"
+ }
+ ]
+ }
+ },
+ "usersTemplate": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "equals",
+ "attribute": "type",
+ "value": "Mail"
+ }
+ ]
+ }
+ },
+ "mailMergeOnlyWithAddress": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "equals",
+ "attribute": "type",
+ "value": "Mail"
+ }
+ ]
+ }
+ }
+ },
+ "panels": {
+ "massEmails": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "in",
+ "attribute": "type",
+ "value": [
+ "Email",
+ "Newsletter",
+ "Informational Email"
+ ]
+ }
+ ]
+ }
+ },
+ "trackingUrls": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "in",
+ "attribute": "type",
+ "value": ["Email", "Newsletter"]
+ }
+ ]
+ }
+ },
+ "mailMerge": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "in",
+ "attribute": "type",
+ "value": ["Mail"]
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/application/Espo/Modules/Crm/Resources/metadata/logicDefs/CampaignTrackingUrl.json b/application/Espo/Modules/Crm/Resources/metadata/logicDefs/CampaignTrackingUrl.json
new file mode 100644
index 0000000000..e5cc25a631
--- /dev/null
+++ b/application/Espo/Modules/Crm/Resources/metadata/logicDefs/CampaignTrackingUrl.json
@@ -0,0 +1,44 @@
+{
+ "fields": {
+ "url": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "equals",
+ "attribute": "action",
+ "value": "Redirect"
+ }
+ ]
+ },
+ "required": {
+ "conditionGroup": [
+ {
+ "type": "equals",
+ "attribute": "action",
+ "value": "Redirect"
+ }
+ ]
+ }
+ },
+ "message": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "equals",
+ "attribute": "action",
+ "value": "Show Message"
+ }
+ ]
+ },
+ "required": {
+ "conditionGroup": [
+ {
+ "type": "equals",
+ "attribute": "action",
+ "value": "Show Message"
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/application/Espo/Modules/Crm/Resources/metadata/logicDefs/Case.json b/application/Espo/Modules/Crm/Resources/metadata/logicDefs/Case.json
new file mode 100644
index 0000000000..170d40a9dc
--- /dev/null
+++ b/application/Espo/Modules/Crm/Resources/metadata/logicDefs/Case.json
@@ -0,0 +1,14 @@
+{
+ "fields": {
+ "number": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isNotEmpty",
+ "attribute": "id"
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/application/Espo/Modules/Crm/Resources/metadata/logicDefs/Contact.json b/application/Espo/Modules/Crm/Resources/metadata/logicDefs/Contact.json
new file mode 100644
index 0000000000..690d2f8be1
--- /dev/null
+++ b/application/Espo/Modules/Crm/Resources/metadata/logicDefs/Contact.json
@@ -0,0 +1,27 @@
+{
+ "fields": {
+ "title": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isNotEmpty",
+ "attribute": "accountId"
+ }
+ ]
+ }
+ },
+ "portalUser": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isNotEmpty",
+ "attribute": "portalUserId",
+ "data": {
+ "field": "portalUser"
+ }
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/application/Espo/Modules/Crm/Resources/metadata/logicDefs/MassEmail.json b/application/Espo/Modules/Crm/Resources/metadata/logicDefs/MassEmail.json
new file mode 100644
index 0000000000..c00fd2979b
--- /dev/null
+++ b/application/Espo/Modules/Crm/Resources/metadata/logicDefs/MassEmail.json
@@ -0,0 +1,59 @@
+{
+ "fields": {
+ "status": {
+ "readOnly": {
+ "conditionGroup": [
+ {
+ "type": "and",
+ "value": [
+ {
+ "type": "or",
+ "value": [
+ {
+ "type": "equals",
+ "attribute": "status",
+ "value": "Complete"
+ },
+ {
+ "type": "equals",
+ "attribute": "status",
+ "value": "In Process"
+ },
+ {
+ "type": "equals",
+ "attribute": "status",
+ "value": "Failed"
+ }
+ ]
+ },
+ {
+ "type": "isNotEmpty",
+ "attribute": "id"
+ }
+ ]
+ }
+ ]
+ }
+ }
+ },
+ "options": {
+ "status": [
+ {
+ "optionList": [
+ "Draft",
+ "Pending"
+ ],
+ "conditionGroup": [
+ {
+ "type": "in",
+ "attribute": "status",
+ "value": [
+ "Draft",
+ "Pending"
+ ]
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/application/Espo/Modules/Crm/Resources/metadata/logicDefs/Opportunity.json b/application/Espo/Modules/Crm/Resources/metadata/logicDefs/Opportunity.json
new file mode 100644
index 0000000000..55aa8622ef
--- /dev/null
+++ b/application/Espo/Modules/Crm/Resources/metadata/logicDefs/Opportunity.json
@@ -0,0 +1,15 @@
+{
+ "fields": {
+ "lastStage": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "equals",
+ "attribute": "stage",
+ "value": "Closed Lost"
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/application/Espo/Modules/Crm/Resources/metadata/logicDefs/TargetList.json b/application/Espo/Modules/Crm/Resources/metadata/logicDefs/TargetList.json
new file mode 100644
index 0000000000..e4ec1b3ece
--- /dev/null
+++ b/application/Espo/Modules/Crm/Resources/metadata/logicDefs/TargetList.json
@@ -0,0 +1,24 @@
+{
+ "fields": {
+ "entryCount": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isNotEmpty",
+ "attribute": "id"
+ }
+ ]
+ }
+ },
+ "optedOutCount": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isNotEmpty",
+ "attribute": "id"
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/application/Espo/Modules/Crm/Resources/metadata/logicDefs/Task.json b/application/Espo/Modules/Crm/Resources/metadata/logicDefs/Task.json
new file mode 100644
index 0000000000..b3f5e720e1
--- /dev/null
+++ b/application/Espo/Modules/Crm/Resources/metadata/logicDefs/Task.json
@@ -0,0 +1,15 @@
+{
+ "fields": {
+ "dateCompleted": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "equals",
+ "attribute": "status",
+ "value": "Completed"
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/application/Espo/Resources/metadata/app/metadata.json b/application/Espo/Resources/metadata/app/metadata.json
index cbd55a45fe..711292ec86 100644
--- a/application/Espo/Resources/metadata/app/metadata.json
+++ b/application/Espo/Resources/metadata/app/metadata.json
@@ -51,6 +51,7 @@
"Espo\\Core\\Utils\\Metadata\\AdditionalBuilder\\Fields",
"Espo\\Core\\Utils\\Metadata\\AdditionalBuilder\\FilterFields",
"Espo\\Core\\Utils\\Metadata\\AdditionalBuilder\\DeleteIdField",
- "Espo\\Core\\Utils\\Metadata\\AdditionalBuilder\\StreamUpdatedAtField"
+ "Espo\\Core\\Utils\\Metadata\\AdditionalBuilder\\StreamUpdatedAtField",
+ "Espo\\Core\\Utils\\Metadata\\AdditionalBuilder\\LogicDefsBc"
]
}
diff --git a/application/Espo/Resources/metadata/clientDefs/Email.json b/application/Espo/Resources/metadata/clientDefs/Email.json
index 5ad05f7289..4fc78750d4 100644
--- a/application/Espo/Resources/metadata/clientDefs/Email.json
+++ b/application/Espo/Resources/metadata/clientDefs/Email.json
@@ -123,84 +123,6 @@
"selectHandler": "handlers/email/select-user"
}
},
- "dynamicLogic":{
- "fields": {
- "replied": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isNotEmpty",
- "attribute": "repliedId",
- "data": {
- "field": "replied"
- }
- }
- ]
- }
- },
- "replies": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isNotEmpty",
- "attribute": "repliesIds",
- "data": {
- "field": "replies"
- }
- }
- ]
- }
- },
- "folderString": {
- "visible": {
- "conditionGroup": [
- {
- "type": "or",
- "value": [
- {
- "type": "and",
- "value": [
- {
- "type": "isTrue",
- "attribute": "isUsers"
- }
- ]
- },
- {
- "type": "isNotEmpty",
- "attribute": "groupFolderId"
- }
- ]
- }
-
- ]
- }
- },
- "sendAt": {
- "visible": {
- "conditionGroup": [
- {
- "type": "in",
- "attribute": "status",
- "value": ["Draft"]
- }
- ]
- }
- }
- },
- "panels": {
- "event": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isNotEmpty",
- "attribute": "icsEventDateStart"
- }
- ]
- }
- }
- }
- },
"filterList":[
],
diff --git a/application/Espo/Resources/metadata/clientDefs/EmailAccount.json b/application/Espo/Resources/metadata/clientDefs/EmailAccount.json
index 948df4754c..130a32c2f6 100644
--- a/application/Espo/Resources/metadata/clientDefs/EmailAccount.json
+++ b/application/Espo/Resources/metadata/clientDefs/EmailAccount.json
@@ -35,55 +35,6 @@
]
}
},
- "dynamicLogic": {
- "fields": {
- "smtpUsername": {
- "required": {
- "conditionGroup": [
- {
- "type": "and",
- "value": [
- {
- "type": "isTrue",
- "attribute": "useSmtp"
- },
- {
- "type": "isTrue",
- "attribute": "smtpAuth"
- }
- ]
- }
- ]
- }
- },
- "fetchSince": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isTrue",
- "attribute": "useImap"
- }
- ]
- },
- "readOnly": {
- "conditionGroup": [
- {
- "type": "isNotEmpty",
- "attribute": "fetchData"
- }
- ]
- },
- "required": {
- "conditionGroup": [
- {
- "type": "isTrue",
- "attribute": "useImap"
- }
- ]
- }
- }
- }
- },
"filterList": [
{
"name": "active"
diff --git a/application/Espo/Resources/metadata/clientDefs/EmailFilter.json b/application/Espo/Resources/metadata/clientDefs/EmailFilter.json
index d999d66067..8dcf3c661b 100644
--- a/application/Espo/Resources/metadata/clientDefs/EmailFilter.json
+++ b/application/Espo/Resources/metadata/clientDefs/EmailFilter.json
@@ -23,137 +23,5 @@
},
"boolFilterList": [
"onlyMy"
- ],
- "dynamicLogic": {
- "fields": {
- "parent": {
- "visible": {
- "conditionGroup": [
- {
- "attribute": "isGlobal",
- "type": "isFalse"
- }
- ]
- },
- "required": {
- "conditionGroup": [
- {
- "attribute": "isGlobal",
- "type": "isFalse"
- }
- ]
- }
- },
- "emailFolder": {
- "visible": {
- "conditionGroup": [
- {
- "attribute": "action",
- "type": "equals",
- "value": "Move to Folder"
- }
- ]
- },
- "required": {
- "conditionGroup": [
- {
- "attribute": "action",
- "type": "equals",
- "value": "Move to Folder"
- }
- ]
- }
- },
- "groupEmailFolder": {
- "visible": {
- "conditionGroup": [
- {
- "attribute": "action",
- "type": "equals",
- "value": "Move to Group Folder"
- }
- ]
- },
- "required": {
- "conditionGroup": [
- {
- "attribute": "action",
- "type": "equals",
- "value": "Move to Group Folder"
- }
- ]
- }
- },
- "markAsRead": {
- "visible": {
- "conditionGroup": [
- {
- "attribute": "parentType",
- "type": "equals",
- "value": "User"
- }
- ]
- }
- },
- "skipNotification": {
- "visible": {
- "conditionGroup": [
- {
- "attribute": "parentType",
- "type": "equals",
- "value": "User"
- }
- ]
- }
- }
- },
- "options": {
- "action": [
- {
- "conditionGroup": [
- {
- "attribute": "isGlobal",
- "type": "isTrue"
- }
- ],
- "optionList": [
- "Skip"
- ]
- },
- {
- "conditionGroup": [
- {
- "attribute": "parentType",
- "type": "equals",
- "value": "User"
- }
- ],
- "optionList": [
- "Skip",
- "Move to Folder",
- "None"
- ]
- },
- {
- "conditionGroup": [
- {
- "attribute": "parentType",
- "type": "equals",
- "value": "InboundEmail"
- }
- ],
- "optionList": [
- "Skip",
- "Move to Group Folder"
- ]
- },
- {
- "conditionGroup": [],
- "optionList": [
- "Skip"
- ]
- }
- ]
- }
- }
+ ]
}
diff --git a/application/Espo/Resources/metadata/clientDefs/InboundEmail.json b/application/Espo/Resources/metadata/clientDefs/InboundEmail.json
index 052da3d5ff..5a5a79ce84 100644
--- a/application/Espo/Resources/metadata/clientDefs/InboundEmail.json
+++ b/application/Espo/Resources/metadata/clientDefs/InboundEmail.json
@@ -29,65 +29,6 @@
]
}
},
- "dynamicLogic": {
- "fields": {
- "smtpUsername": {
- "required": {
- "conditionGroup": [
- {
- "type": "and",
- "value": [
- {
- "type": "isTrue",
- "attribute": "useSmtp"
- },
- {
- "type": "isTrue",
- "attribute": "smtpAuth"
- }
- ]
- }
- ]
- }
- },
- "fetchSince": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isTrue",
- "attribute": "useImap"
- }
- ]
- },
- "readOnly": {
- "conditionGroup": [
- {
- "type": "isNotEmpty",
- "attribute": "fetchData"
- }
- ]
- },
- "required": {
- "conditionGroup": [
- {
- "type": "isTrue",
- "attribute": "useImap"
- }
- ]
- }
- },
- "isSystem": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isNotEmpty",
- "attribute": "id"
- }
- ]
- }
- }
- }
- },
"searchPanelDisabled": true,
"relationshipPanels": {
"filters": {
diff --git a/application/Espo/Resources/metadata/clientDefs/LeadCapture.json b/application/Espo/Resources/metadata/clientDefs/LeadCapture.json
index 0422368825..ece82f4efb 100644
--- a/application/Espo/Resources/metadata/clientDefs/LeadCapture.json
+++ b/application/Espo/Resources/metadata/clientDefs/LeadCapture.json
@@ -5,243 +5,6 @@
"detail": "views/lead-capture/record/detail",
"list": "views/lead-capture/record/list"
},
- "dynamicLogic": {
- "fields": {
- "targetList": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isTrue",
- "attribute": "subscribeToTargetList"
- }
- ]
- },
- "required": {
- "conditionGroup": [
- {
- "type": "isTrue",
- "attribute": "subscribeToTargetList"
- }
- ]
- }
- },
- "subscribeContactToTargetList": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isTrue",
- "attribute": "subscribeToTargetList"
- }
- ]
- }
- },
- "optInConfirmationLifetime": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isTrue",
- "attribute": "optInConfirmation"
- }
- ]
- },
- "required": {
- "conditionGroup": [
- {
- "type": "isTrue",
- "attribute": "optInConfirmation"
- }
- ]
- }
- },
- "optInConfirmationSuccessMessage": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isTrue",
- "attribute": "optInConfirmation"
- }
- ]
- }
- },
- "createLeadBeforeOptInConfirmation": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isTrue",
- "attribute": "optInConfirmation"
- }
- ]
- }
- },
- "smtpAccount": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isTrue",
- "attribute": "optInConfirmation"
- }
- ]
- }
- },
- "skipOptInConfirmationIfSubscribed": {
- "visible": {
- "conditionGroup": [
- {
- "type": "and",
- "value": [
- {
- "type": "isTrue",
- "attribute": "optInConfirmation"
- },
- {
- "type": "isNotEmpty",
- "attribute": "targetListId",
- "data": {
- "field": "targetList"
- }
- }
- ]
- }
- ]
- }
- },
- "optInConfirmationEmailTemplate": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isTrue",
- "attribute": "optInConfirmation"
- }
- ]
- },
- "required": {
- "conditionGroup": [
- {
- "type": "isTrue",
- "attribute": "optInConfirmation"
- }
- ]
- }
- },
- "apiKey": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isNotEmpty",
- "attribute": "id"
- }
- ]
- }
- },
- "phoneNumberCountry": {
- "visible": {
- "conditionGroup": [
- {
- "type": "contains",
- "attribute": "fieldList",
- "value": "phoneNumber"
- }
- ]
- }
- },
- "formSuccessText": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isTrue",
- "attribute": "formEnabled"
- }
- ]
- }
- },
- "formTitle": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isTrue",
- "attribute": "formEnabled"
- }
- ]
- }
- },
- "formTheme": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isTrue",
- "attribute": "formEnabled"
- }
- ]
- }
- },
- "formText": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isTrue",
- "attribute": "formEnabled"
- }
- ]
- }
- },
- "formSuccessRedirectUrl": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isTrue",
- "attribute": "formEnabled"
- }
- ]
- }
- },
- "formLanguage": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isTrue",
- "attribute": "formEnabled"
- }
- ]
- }
- },
- "formFrameAncestors": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isTrue",
- "attribute": "formEnabled"
- }
- ]
- }
- },
- "formCaptcha": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isTrue",
- "attribute": "formEnabled"
- }
- ]
- }
- }
- },
- "panels": {
- "form": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isNotEmpty",
- "attribute": "id"
- },
- {
- "type": "isTrue",
- "attribute": "formEnabled"
- }
- ]
- }
- }
- }
- },
"sidePanels": {
"detail": [
{
diff --git a/application/Espo/Resources/metadata/clientDefs/OAuthProvider.json b/application/Espo/Resources/metadata/clientDefs/OAuthProvider.json
index 035c56421c..4e8be86087 100644
--- a/application/Espo/Resources/metadata/clientDefs/OAuthProvider.json
+++ b/application/Espo/Resources/metadata/clientDefs/OAuthProvider.json
@@ -6,59 +6,5 @@
"selectDisabled": true,
"unlinkDisabled": true
}
- },
- "dynamicLogic": {
- "fields": {
- "authorizationRedirectUri": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isNotEmpty",
- "attribute": "id"
- }
- ]
- }
- },
- "clientId": {
- "required": {
- "conditionGroup": [
- {
- "type": "isTrue",
- "attribute": "isActive"
- }
- ]
- }
- },
- "clientSecret": {
- "required": {
- "conditionGroup": [
- {
- "type": "isTrue",
- "attribute": "isActive"
- }
- ]
- }
- },
- "authorizationEndpoint": {
- "required": {
- "conditionGroup": [
- {
- "type": "isTrue",
- "attribute": "isActive"
- }
- ]
- }
- },
- "tokenEndpoint": {
- "required": {
- "conditionGroup": [
- {
- "type": "isTrue",
- "attribute": "isActive"
- }
- ]
- }
- }
- }
}
}
diff --git a/application/Espo/Resources/metadata/clientDefs/Preferences.json b/application/Espo/Resources/metadata/clientDefs/Preferences.json
index 5bbc002591..dde139f74e 100644
--- a/application/Espo/Resources/metadata/clientDefs/Preferences.json
+++ b/application/Espo/Resources/metadata/clientDefs/Preferences.json
@@ -6,19 +6,5 @@
"edit": "views/preferences/edit"
},
"acl": "acl/preferences",
- "aclPortal": "acl-portal/preferences",
- "dynamicLogic": {
- "fields": {
- "assignmentEmailNotificationsIgnoreEntityTypeList": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isTrue",
- "attribute": "receiveAssignmentEmailNotifications"
- }
- ]
- }
- }
- }
- }
+ "aclPortal": "acl-portal/preferences"
}
diff --git a/application/Espo/Resources/metadata/clientDefs/Template.json b/application/Espo/Resources/metadata/clientDefs/Template.json
index 715f4e8972..3ab2902902 100644
--- a/application/Espo/Resources/metadata/clientDefs/Template.json
+++ b/application/Espo/Resources/metadata/clientDefs/Template.json
@@ -5,109 +5,5 @@
"edit": "views/template/record/edit"
},
"mergeDisabled": true,
- "dynamicLogic": {
- "fields": {
- "entityType": {
- "readOnly": {
- "conditionGroup": [
- {
- "type": "isNotEmpty",
- "attribute": "id"
- }
- ]
- }
- },
- "footer": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isTrue",
- "attribute": "printFooter"
- }
- ]
- }
- },
- "footerPosition": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isTrue",
- "attribute": "printFooter"
- }
- ]
- }
- },
- "header": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isTrue",
- "attribute": "printHeader"
- }
- ]
- }
- },
- "headerPosition": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isTrue",
- "attribute": "printHeader"
- }
- ]
- }
- },
- "body": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isNotEmpty",
- "attribute": "entityType"
- }
- ]
- }
- },
- "pageWidth": {
- "visible": {
- "conditionGroup": [
- {
- "type": "equals",
- "attribute": "pageFormat",
- "value": "Custom"
- }
- ]
- },
- "required": {
- "conditionGroup": [
- {
- "type": "equals",
- "attribute": "pageFormat",
- "value": "Custom"
- }
- ]
- }
- },
- "pageHeight": {
- "visible": {
- "conditionGroup": [
- {
- "type": "equals",
- "attribute": "pageFormat",
- "value": "Custom"
- }
- ]
- },
- "required": {
- "conditionGroup": [
- {
- "type": "equals",
- "attribute": "pageFormat",
- "value": "Custom"
- }
- ]
- }
- }
- }
- },
"iconClass": "fas fa-file-pdf"
}
diff --git a/application/Espo/Resources/metadata/clientDefs/User.json b/application/Espo/Resources/metadata/clientDefs/User.json
index 8ecbbfe6a5..e3286d0c21 100644
--- a/application/Espo/Resources/metadata/clientDefs/User.json
+++ b/application/Espo/Resources/metadata/clientDefs/User.json
@@ -122,49 +122,5 @@
"selectRecords": {
"orderBy": "userNameOwnFirst"
},
- "iconClass": "fas fa-user-circle",
- "dynamicLogic": {
- "fields": {
- "avatarColor": {
- "visible": {
- "conditionGroup": [
- {
- "type": "equals",
- "attribute": "avatarId",
- "value": null,
- "data": {
- "field": "avatar"
- }
- },
- {
- "type": "in",
- "attribute": "type",
- "value": [
- "regular",
- "admin",
- "api"
- ]
- }
- ]
- }
- }
- },
- "options": {
- "authMethod": [
- {
- "optionList": [
- "ApiKey",
- "Hmac"
- ],
- "conditionGroup": [
- {
- "type": "equals",
- "attribute": "type",
- "value": "api"
- }
- ]
- }
- ]
- }
- }
+ "iconClass": "fas fa-user-circle"
}
diff --git a/application/Espo/Resources/metadata/clientDefs/Webhook.json b/application/Espo/Resources/metadata/clientDefs/Webhook.json
index 09840f734d..625b2b8ad2 100644
--- a/application/Espo/Resources/metadata/clientDefs/Webhook.json
+++ b/application/Espo/Resources/metadata/clientDefs/Webhook.json
@@ -14,29 +14,5 @@
}
]
}
- },
- "dynamicLogic": {
- "fields": {
- "event": {
- "readOnly": {
- "conditionGroup": [
- {
- "type": "isNotEmpty",
- "attribute": "id"
- }
- ]
- }
- },
- "secretKey": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isNotEmpty",
- "attribute": "id"
- }
- ]
- }
- }
- }
}
}
diff --git a/application/Espo/Resources/metadata/clientDefs/WorkingTimeCalendar.json b/application/Espo/Resources/metadata/clientDefs/WorkingTimeCalendar.json
index 30b5edd337..d9eb0151e8 100644
--- a/application/Espo/Resources/metadata/clientDefs/WorkingTimeCalendar.json
+++ b/application/Espo/Resources/metadata/clientDefs/WorkingTimeCalendar.json
@@ -15,89 +15,5 @@
}
]
}
- },
- "dynamicLogic": {
- "fields": {
- "weekday0TimeRanges": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isTrue",
- "attribute": "weekday0"
- }
- ]
- }
- },
- "weekday1TimeRanges": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isTrue",
- "attribute": "weekday1"
- }
- ]
- }
- },
- "weekday2TimeRanges": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isTrue",
- "attribute": "weekday2"
- }
- ]
- }
- },
- "weekday3TimeRanges": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isTrue",
- "attribute": "weekday3"
- }
- ]
- }
- },
- "weekday4TimeRanges": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isTrue",
- "attribute": "weekday4"
- }
- ]
- }
- },
- "weekday5TimeRanges": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isTrue",
- "attribute": "weekday5"
- }
- ]
- }
- },
- "weekday6TimeRanges": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isTrue",
- "attribute": "weekday6"
- }
- ]
- }
- },
- "teams": {
- "visible": {
- "conditionGroup": [
- {
- "type": "isNotEmpty",
- "attribute": "teamsIds"
- }
- ]
- }
- }
- }
}
}
diff --git a/application/Espo/Resources/metadata/clientDefs/WorkingTimeRange.json b/application/Espo/Resources/metadata/clientDefs/WorkingTimeRange.json
index 48a283cb61..a5ed3c670b 100644
--- a/application/Espo/Resources/metadata/clientDefs/WorkingTimeRange.json
+++ b/application/Espo/Resources/metadata/clientDefs/WorkingTimeRange.json
@@ -16,44 +16,6 @@
]
}
},
- "dynamicLogic": {
- "fields": {
- "timeRanges": {
- "visible": {
- "conditionGroup": [
- {
- "type": "equals",
- "attribute": "type",
- "value": "Working"
- }
- ]
- }
- },
- "users": {
- "visible": {
- "conditionGroup": [
- {
- "type": "or",
- "value": [
- {
- "type": "isNotEmpty",
- "attribute": "id"
- },
- {
- "type": "isNotEmpty",
- "attribute": "usersIds"
- },
- {
- "type": "isEmpty",
- "attribute": "calendarsIds"
- }
- ]
- }
- ]
- }
- }
- }
- },
"filterList": [
"actual"
]
diff --git a/application/Espo/Resources/metadata/logicDefs/Email.json b/application/Espo/Resources/metadata/logicDefs/Email.json
new file mode 100644
index 0000000000..910ca23d7b
--- /dev/null
+++ b/application/Espo/Resources/metadata/logicDefs/Email.json
@@ -0,0 +1,78 @@
+{
+ "fields": {
+ "replied": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isNotEmpty",
+ "attribute": "repliedId",
+ "data": {
+ "field": "replied"
+ }
+ }
+ ]
+ }
+ },
+ "replies": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isNotEmpty",
+ "attribute": "repliesIds",
+ "data": {
+ "field": "replies"
+ }
+ }
+ ]
+ }
+ },
+ "folderString": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "or",
+ "value": [
+ {
+ "type": "and",
+ "value": [
+ {
+ "type": "isTrue",
+ "attribute": "isUsers"
+ }
+ ]
+ },
+ {
+ "type": "isNotEmpty",
+ "attribute": "groupFolderId"
+ }
+ ]
+ }
+
+ ]
+ }
+ },
+ "sendAt": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "in",
+ "attribute": "status",
+ "value": ["Draft"]
+ }
+ ]
+ }
+ }
+ },
+ "panels": {
+ "event": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isNotEmpty",
+ "attribute": "icsEventDateStart"
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/application/Espo/Resources/metadata/logicDefs/EmailAccount.json b/application/Espo/Resources/metadata/logicDefs/EmailAccount.json
new file mode 100644
index 0000000000..d7836314a2
--- /dev/null
+++ b/application/Espo/Resources/metadata/logicDefs/EmailAccount.json
@@ -0,0 +1,49 @@
+{
+ "fields": {
+ "smtpUsername": {
+ "required": {
+ "conditionGroup": [
+ {
+ "type": "and",
+ "value": [
+ {
+ "type": "isTrue",
+ "attribute": "useSmtp"
+ },
+ {
+ "type": "isTrue",
+ "attribute": "smtpAuth"
+ }
+ ]
+ }
+ ]
+ }
+ },
+ "fetchSince": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isTrue",
+ "attribute": "useImap"
+ }
+ ]
+ },
+ "readOnly": {
+ "conditionGroup": [
+ {
+ "type": "isNotEmpty",
+ "attribute": "fetchData"
+ }
+ ]
+ },
+ "required": {
+ "conditionGroup": [
+ {
+ "type": "isTrue",
+ "attribute": "useImap"
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/application/Espo/Resources/metadata/logicDefs/EmailFilter.json b/application/Espo/Resources/metadata/logicDefs/EmailFilter.json
new file mode 100644
index 0000000000..a3ec579283
--- /dev/null
+++ b/application/Espo/Resources/metadata/logicDefs/EmailFilter.json
@@ -0,0 +1,132 @@
+{
+ "fields": {
+ "parent": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "attribute": "isGlobal",
+ "type": "isFalse"
+ }
+ ]
+ },
+ "required": {
+ "conditionGroup": [
+ {
+ "attribute": "isGlobal",
+ "type": "isFalse"
+ }
+ ]
+ }
+ },
+ "emailFolder": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "attribute": "action",
+ "type": "equals",
+ "value": "Move to Folder"
+ }
+ ]
+ },
+ "required": {
+ "conditionGroup": [
+ {
+ "attribute": "action",
+ "type": "equals",
+ "value": "Move to Folder"
+ }
+ ]
+ }
+ },
+ "groupEmailFolder": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "attribute": "action",
+ "type": "equals",
+ "value": "Move to Group Folder"
+ }
+ ]
+ },
+ "required": {
+ "conditionGroup": [
+ {
+ "attribute": "action",
+ "type": "equals",
+ "value": "Move to Group Folder"
+ }
+ ]
+ }
+ },
+ "markAsRead": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "attribute": "parentType",
+ "type": "equals",
+ "value": "User"
+ }
+ ]
+ }
+ },
+ "skipNotification": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "attribute": "parentType",
+ "type": "equals",
+ "value": "User"
+ }
+ ]
+ }
+ }
+ },
+ "options": {
+ "action": [
+ {
+ "conditionGroup": [
+ {
+ "attribute": "isGlobal",
+ "type": "isTrue"
+ }
+ ],
+ "optionList": [
+ "Skip"
+ ]
+ },
+ {
+ "conditionGroup": [
+ {
+ "attribute": "parentType",
+ "type": "equals",
+ "value": "User"
+ }
+ ],
+ "optionList": [
+ "Skip",
+ "Move to Folder",
+ "None"
+ ]
+ },
+ {
+ "conditionGroup": [
+ {
+ "attribute": "parentType",
+ "type": "equals",
+ "value": "InboundEmail"
+ }
+ ],
+ "optionList": [
+ "Skip",
+ "Move to Group Folder"
+ ]
+ },
+ {
+ "conditionGroup": [],
+ "optionList": [
+ "Skip"
+ ]
+ }
+ ]
+ }
+}
diff --git a/application/Espo/Resources/metadata/logicDefs/InboundEmail.json b/application/Espo/Resources/metadata/logicDefs/InboundEmail.json
new file mode 100644
index 0000000000..dfcc5813e8
--- /dev/null
+++ b/application/Espo/Resources/metadata/logicDefs/InboundEmail.json
@@ -0,0 +1,59 @@
+{
+ "fields": {
+ "smtpUsername": {
+ "required": {
+ "conditionGroup": [
+ {
+ "type": "and",
+ "value": [
+ {
+ "type": "isTrue",
+ "attribute": "useSmtp"
+ },
+ {
+ "type": "isTrue",
+ "attribute": "smtpAuth"
+ }
+ ]
+ }
+ ]
+ }
+ },
+ "fetchSince": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isTrue",
+ "attribute": "useImap"
+ }
+ ]
+ },
+ "readOnly": {
+ "conditionGroup": [
+ {
+ "type": "isNotEmpty",
+ "attribute": "fetchData"
+ }
+ ]
+ },
+ "required": {
+ "conditionGroup": [
+ {
+ "type": "isTrue",
+ "attribute": "useImap"
+ }
+ ]
+ }
+ },
+ "isSystem": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isNotEmpty",
+ "attribute": "id"
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/application/Espo/Resources/metadata/logicDefs/LeadCapture.json b/application/Espo/Resources/metadata/logicDefs/LeadCapture.json
new file mode 100644
index 0000000000..f339c46a75
--- /dev/null
+++ b/application/Espo/Resources/metadata/logicDefs/LeadCapture.json
@@ -0,0 +1,237 @@
+{
+ "fields": {
+ "targetList": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isTrue",
+ "attribute": "subscribeToTargetList"
+ }
+ ]
+ },
+ "required": {
+ "conditionGroup": [
+ {
+ "type": "isTrue",
+ "attribute": "subscribeToTargetList"
+ }
+ ]
+ }
+ },
+ "subscribeContactToTargetList": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isTrue",
+ "attribute": "subscribeToTargetList"
+ }
+ ]
+ }
+ },
+ "optInConfirmationLifetime": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isTrue",
+ "attribute": "optInConfirmation"
+ }
+ ]
+ },
+ "required": {
+ "conditionGroup": [
+ {
+ "type": "isTrue",
+ "attribute": "optInConfirmation"
+ }
+ ]
+ }
+ },
+ "optInConfirmationSuccessMessage": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isTrue",
+ "attribute": "optInConfirmation"
+ }
+ ]
+ }
+ },
+ "createLeadBeforeOptInConfirmation": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isTrue",
+ "attribute": "optInConfirmation"
+ }
+ ]
+ }
+ },
+ "smtpAccount": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isTrue",
+ "attribute": "optInConfirmation"
+ }
+ ]
+ }
+ },
+ "skipOptInConfirmationIfSubscribed": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "and",
+ "value": [
+ {
+ "type": "isTrue",
+ "attribute": "optInConfirmation"
+ },
+ {
+ "type": "isNotEmpty",
+ "attribute": "targetListId",
+ "data": {
+ "field": "targetList"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ },
+ "optInConfirmationEmailTemplate": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isTrue",
+ "attribute": "optInConfirmation"
+ }
+ ]
+ },
+ "required": {
+ "conditionGroup": [
+ {
+ "type": "isTrue",
+ "attribute": "optInConfirmation"
+ }
+ ]
+ }
+ },
+ "apiKey": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isNotEmpty",
+ "attribute": "id"
+ }
+ ]
+ }
+ },
+ "phoneNumberCountry": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "contains",
+ "attribute": "fieldList",
+ "value": "phoneNumber"
+ }
+ ]
+ }
+ },
+ "formSuccessText": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isTrue",
+ "attribute": "formEnabled"
+ }
+ ]
+ }
+ },
+ "formTitle": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isTrue",
+ "attribute": "formEnabled"
+ }
+ ]
+ }
+ },
+ "formTheme": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isTrue",
+ "attribute": "formEnabled"
+ }
+ ]
+ }
+ },
+ "formText": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isTrue",
+ "attribute": "formEnabled"
+ }
+ ]
+ }
+ },
+ "formSuccessRedirectUrl": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isTrue",
+ "attribute": "formEnabled"
+ }
+ ]
+ }
+ },
+ "formLanguage": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isTrue",
+ "attribute": "formEnabled"
+ }
+ ]
+ }
+ },
+ "formFrameAncestors": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isTrue",
+ "attribute": "formEnabled"
+ }
+ ]
+ }
+ },
+ "formCaptcha": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isTrue",
+ "attribute": "formEnabled"
+ }
+ ]
+ }
+ }
+ },
+ "panels": {
+ "form": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isNotEmpty",
+ "attribute": "id"
+ },
+ {
+ "type": "isTrue",
+ "attribute": "formEnabled"
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/application/Espo/Resources/metadata/logicDefs/OAuthProvider.json b/application/Espo/Resources/metadata/logicDefs/OAuthProvider.json
new file mode 100644
index 0000000000..5334e22906
--- /dev/null
+++ b/application/Espo/Resources/metadata/logicDefs/OAuthProvider.json
@@ -0,0 +1,54 @@
+{
+ "fields": {
+ "authorizationRedirectUri": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isNotEmpty",
+ "attribute": "id"
+ }
+ ]
+ }
+ },
+ "clientId": {
+ "required": {
+ "conditionGroup": [
+ {
+ "type": "isTrue",
+ "attribute": "isActive"
+ }
+ ]
+ }
+ },
+ "clientSecret": {
+ "required": {
+ "conditionGroup": [
+ {
+ "type": "isTrue",
+ "attribute": "isActive"
+ }
+ ]
+ }
+ },
+ "authorizationEndpoint": {
+ "required": {
+ "conditionGroup": [
+ {
+ "type": "isTrue",
+ "attribute": "isActive"
+ }
+ ]
+ }
+ },
+ "tokenEndpoint": {
+ "required": {
+ "conditionGroup": [
+ {
+ "type": "isTrue",
+ "attribute": "isActive"
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/application/Espo/Resources/metadata/logicDefs/Preferences.json b/application/Espo/Resources/metadata/logicDefs/Preferences.json
new file mode 100644
index 0000000000..7f532297bd
--- /dev/null
+++ b/application/Espo/Resources/metadata/logicDefs/Preferences.json
@@ -0,0 +1,14 @@
+{
+ "fields": {
+ "assignmentEmailNotificationsIgnoreEntityTypeList": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isTrue",
+ "attribute": "receiveAssignmentEmailNotifications"
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/application/Espo/Resources/metadata/logicDefs/Template.json b/application/Espo/Resources/metadata/logicDefs/Template.json
new file mode 100644
index 0000000000..324097ad0e
--- /dev/null
+++ b/application/Espo/Resources/metadata/logicDefs/Template.json
@@ -0,0 +1,104 @@
+{
+ "fields": {
+ "entityType": {
+ "readOnly": {
+ "conditionGroup": [
+ {
+ "type": "isNotEmpty",
+ "attribute": "id"
+ }
+ ]
+ }
+ },
+ "footer": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isTrue",
+ "attribute": "printFooter"
+ }
+ ]
+ }
+ },
+ "footerPosition": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isTrue",
+ "attribute": "printFooter"
+ }
+ ]
+ }
+ },
+ "header": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isTrue",
+ "attribute": "printHeader"
+ }
+ ]
+ }
+ },
+ "headerPosition": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isTrue",
+ "attribute": "printHeader"
+ }
+ ]
+ }
+ },
+ "body": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isNotEmpty",
+ "attribute": "entityType"
+ }
+ ]
+ }
+ },
+ "pageWidth": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "equals",
+ "attribute": "pageFormat",
+ "value": "Custom"
+ }
+ ]
+ },
+ "required": {
+ "conditionGroup": [
+ {
+ "type": "equals",
+ "attribute": "pageFormat",
+ "value": "Custom"
+ }
+ ]
+ }
+ },
+ "pageHeight": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "equals",
+ "attribute": "pageFormat",
+ "value": "Custom"
+ }
+ ]
+ },
+ "required": {
+ "conditionGroup": [
+ {
+ "type": "equals",
+ "attribute": "pageFormat",
+ "value": "Custom"
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/application/Espo/Resources/metadata/logicDefs/User.json b/application/Espo/Resources/metadata/logicDefs/User.json
new file mode 100644
index 0000000000..47ecd81970
--- /dev/null
+++ b/application/Espo/Resources/metadata/logicDefs/User.json
@@ -0,0 +1,44 @@
+{
+ "fields": {
+ "avatarColor": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "equals",
+ "attribute": "avatarId",
+ "value": null,
+ "data": {
+ "field": "avatar"
+ }
+ },
+ {
+ "type": "in",
+ "attribute": "type",
+ "value": [
+ "regular",
+ "admin",
+ "api"
+ ]
+ }
+ ]
+ }
+ }
+ },
+ "options": {
+ "authMethod": [
+ {
+ "optionList": [
+ "ApiKey",
+ "Hmac"
+ ],
+ "conditionGroup": [
+ {
+ "type": "equals",
+ "attribute": "type",
+ "value": "api"
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/application/Espo/Resources/metadata/logicDefs/Webhook.json b/application/Espo/Resources/metadata/logicDefs/Webhook.json
new file mode 100644
index 0000000000..f30caca6bb
--- /dev/null
+++ b/application/Espo/Resources/metadata/logicDefs/Webhook.json
@@ -0,0 +1,24 @@
+{
+ "fields": {
+ "event": {
+ "readOnly": {
+ "conditionGroup": [
+ {
+ "type": "isNotEmpty",
+ "attribute": "id"
+ }
+ ]
+ }
+ },
+ "secretKey": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isNotEmpty",
+ "attribute": "id"
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/application/Espo/Resources/metadata/logicDefs/WorkingTimeCalendar.json b/application/Espo/Resources/metadata/logicDefs/WorkingTimeCalendar.json
new file mode 100644
index 0000000000..fdccd8ba44
--- /dev/null
+++ b/application/Espo/Resources/metadata/logicDefs/WorkingTimeCalendar.json
@@ -0,0 +1,84 @@
+{
+ "fields": {
+ "weekday0TimeRanges": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isTrue",
+ "attribute": "weekday0"
+ }
+ ]
+ }
+ },
+ "weekday1TimeRanges": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isTrue",
+ "attribute": "weekday1"
+ }
+ ]
+ }
+ },
+ "weekday2TimeRanges": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isTrue",
+ "attribute": "weekday2"
+ }
+ ]
+ }
+ },
+ "weekday3TimeRanges": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isTrue",
+ "attribute": "weekday3"
+ }
+ ]
+ }
+ },
+ "weekday4TimeRanges": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isTrue",
+ "attribute": "weekday4"
+ }
+ ]
+ }
+ },
+ "weekday5TimeRanges": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isTrue",
+ "attribute": "weekday5"
+ }
+ ]
+ }
+ },
+ "weekday6TimeRanges": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isTrue",
+ "attribute": "weekday6"
+ }
+ ]
+ }
+ },
+ "teams": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "isNotEmpty",
+ "attribute": "teamsIds"
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/application/Espo/Resources/metadata/logicDefs/WorkingTimeRange.json b/application/Espo/Resources/metadata/logicDefs/WorkingTimeRange.json
new file mode 100644
index 0000000000..605b9f7262
--- /dev/null
+++ b/application/Espo/Resources/metadata/logicDefs/WorkingTimeRange.json
@@ -0,0 +1,38 @@
+{
+ "fields": {
+ "timeRanges": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "equals",
+ "attribute": "type",
+ "value": "Working"
+ }
+ ]
+ }
+ },
+ "users": {
+ "visible": {
+ "conditionGroup": [
+ {
+ "type": "or",
+ "value": [
+ {
+ "type": "isNotEmpty",
+ "attribute": "id"
+ },
+ {
+ "type": "isNotEmpty",
+ "attribute": "usersIds"
+ },
+ {
+ "type": "isEmpty",
+ "attribute": "calendarsIds"
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/application/Espo/Tools/App/MetadataService.php b/application/Espo/Tools/App/MetadataService.php
index c4beac001f..79938e0e93 100644
--- a/application/Espo/Tools/App/MetadataService.php
+++ b/application/Espo/Tools/App/MetadataService.php
@@ -92,6 +92,7 @@ class MetadataService
unset($data->clientDefs->$scope);
unset($data->entityAcl->$scope);
unset($data->scopes->$scope);
+ unset($data->logicDefs->$scope);
}
}
diff --git a/application/Espo/Tools/EntityManager/Rename/MetadataType.php b/application/Espo/Tools/EntityManager/Rename/MetadataType.php
index 0339aab556..6b5fe04ed9 100644
--- a/application/Espo/Tools/EntityManager/Rename/MetadataType.php
+++ b/application/Espo/Tools/EntityManager/Rename/MetadataType.php
@@ -50,4 +50,6 @@ class MetadataType
public const PDF_DEFS = 'pdfDefs';
public const FORMULA = 'formula';
+
+ public const LOGIC_DEFS = 'logicDefs';
}
diff --git a/application/Espo/Tools/EntityManager/Rename/Renamer.php b/application/Espo/Tools/EntityManager/Rename/Renamer.php
index fb15fa94d2..23ac817da7 100644
--- a/application/Espo/Tools/EntityManager/Rename/Renamer.php
+++ b/application/Espo/Tools/EntityManager/Rename/Renamer.php
@@ -75,6 +75,7 @@ class Renamer
MetadataType::RECORD_DEFS,
MetadataType::SCOPES,
MetadataType::SELECT_DEFS,
+ MetadataType::LOGIC_DEFS,
];
private NameUtil $nameUtil;
diff --git a/application/Espo/Tools/FieldManager/FieldManager.php b/application/Espo/Tools/FieldManager/FieldManager.php
index 527a619435..29d5fd58fd 100644
--- a/application/Espo/Tools/FieldManager/FieldManager.php
+++ b/application/Espo/Tools/FieldManager/FieldManager.php
@@ -300,106 +300,95 @@ class FieldManager
}
$metadataToBeSaved = false;
- $clientDefsToBeSet = false;
+ $logicDefsToBeSet = false;
- $clientDefs = [];
+ $logicDefs = [];
if (array_key_exists('dynamicLogicVisible', $fieldDefs)) {
if (!is_null($fieldDefs['dynamicLogicVisible'])) {
- $this->prepareClientDefsFieldsDynamicLogic($clientDefs, $name);
+ $this->prepareLogicDefsFields($logicDefs, $name);
- $clientDefs['dynamicLogic']['fields'][$name]['visible'] = $fieldDefs['dynamicLogicVisible'];
+ $logicDefs['fields'][$name]['visible'] = $fieldDefs['dynamicLogicVisible'];
- $clientDefsToBeSet = true;
- } else {
- if (
- $this->metadata->get(['clientDefs', $scope, 'dynamicLogic', 'fields', $name, 'visible'])
- ) {
- $this->prepareClientDefsFieldsDynamicLogic($clientDefs, $name);
+ $logicDefsToBeSet = true;
+ } else if ($this->metadata->get(['logicDefs', $scope, 'fields', $name, 'visible'])) {
+ $this->prepareLogicDefsFields($logicDefs, $name);
- $clientDefs['dynamicLogic']['fields'][$name]['visible'] = null;
- $clientDefsToBeSet = true;
- }
+ $logicDefs['fields'][$name]['visible'] = null;
+ $logicDefsToBeSet = true;
}
}
if (array_key_exists('dynamicLogicReadOnly', $fieldDefs)) {
if (!is_null($fieldDefs['dynamicLogicReadOnly'])) {
- $this->prepareClientDefsFieldsDynamicLogic($clientDefs, $name);
+ $this->prepareLogicDefsFields($logicDefs, $name);
- $clientDefs['dynamicLogic']['fields'][$name]['readOnly'] = $fieldDefs['dynamicLogicReadOnly'];
- $clientDefsToBeSet = true;
- } else {
- if (
- $this->metadata->get(['clientDefs', $scope, 'dynamicLogic', 'fields', $name, 'readOnly'])
- ) {
- $this->prepareClientDefsFieldsDynamicLogic($clientDefs, $name);
+ $logicDefs['fields'][$name]['readOnly'] = $fieldDefs['dynamicLogicReadOnly'];
+ $logicDefsToBeSet = true;
+ } else if ($this->metadata->get(['logicDefs', $scope, 'fields', $name, 'readOnly'])) {
+ $this->prepareLogicDefsFields($logicDefs, $name);
- $clientDefs['dynamicLogic']['fields'][$name]['readOnly'] = null;
+ $logicDefs['fields'][$name]['readOnly'] = null;
- $clientDefsToBeSet = true;
- }
+ $logicDefsToBeSet = true;
}
}
if (array_key_exists('dynamicLogicRequired', $fieldDefs)) {
if (!is_null($fieldDefs['dynamicLogicRequired'])) {
- $this->prepareClientDefsFieldsDynamicLogic($clientDefs, $name);
+ $this->prepareLogicDefsFields($logicDefs, $name);
- $clientDefs['dynamicLogic']['fields'][$name]['required'] = $fieldDefs['dynamicLogicRequired'];
- $clientDefsToBeSet = true;
- } else {
- if (
- $this->metadata->get(['clientDefs', $scope, 'dynamicLogic', 'fields', $name, 'required'])
- ) {
- $this->prepareClientDefsFieldsDynamicLogic($clientDefs, $name);
+ $logicDefs['fields'][$name]['required'] = $fieldDefs['dynamicLogicRequired'];
+ $logicDefsToBeSet = true;
+ } else if ($this->metadata->get(['logicDefs', $scope, 'fields', $name, 'required'])) {
+ $this->prepareLogicDefsFields($logicDefs, $name);
- $clientDefs['dynamicLogic']['fields'][$name]['required'] = null;
+ $logicDefs['fields'][$name]['required'] = null;
- $clientDefsToBeSet = true;
- }
+ $logicDefsToBeSet = true;
}
}
if (array_key_exists('dynamicLogicOptions', $fieldDefs)) {
if (!is_null($fieldDefs['dynamicLogicOptions'])) {
- $this->prepareClientDefsOptionsDynamicLogic($clientDefs, $name);
+ $this->prepareLogicDefsOptions($logicDefs, $name);
- $clientDefs['dynamicLogic']['options'][$name] = $fieldDefs['dynamicLogicOptions'];
+ $logicDefs['options'][$name] = $fieldDefs['dynamicLogicOptions'];
- $clientDefsToBeSet = true;
+ $logicDefsToBeSet = true;
} else {
- if ($this->metadata->get(['clientDefs', $scope, 'dynamicLogic', 'options', $name])) {
- $this->prepareClientDefsOptionsDynamicLogic($clientDefs, $name);
+ if ($this->metadata->get(['logicDefs', $scope, 'options', $name])) {
+ $this->prepareLogicDefsOptions($logicDefs, $name);
- $clientDefs['dynamicLogic']['options'][$name] = null;
+ $logicDefs['options'][$name] = null;
- $clientDefsToBeSet = true;
+ $logicDefsToBeSet = true;
}
}
}
if (array_key_exists('dynamicLogicInvalid', $fieldDefs)) {
if (!is_null($fieldDefs['dynamicLogicInvalid'])) {
- $this->prepareClientDefsFieldsDynamicLogic($clientDefs, $name);
+ $this->prepareLogicDefsFields($logicDefs, $name);
- $clientDefs['dynamicLogic']['fields'][$name]['invalid'] = $fieldDefs['dynamicLogicInvalid'];
- $clientDefsToBeSet = true;
+ $logicDefs['fields'][$name]['invalid'] = $fieldDefs['dynamicLogicInvalid'];
+
+ $logicDefsToBeSet = true;
} else {
if (
- $this->metadata->get(['clientDefs', $scope, 'dynamicLogic', 'fields', $name, 'invalid'])
+ $this->metadata->get(['logicDefs', $scope, 'fields', $name, 'invalid'])
) {
- $this->prepareClientDefsFieldsDynamicLogic($clientDefs, $name);
+ $this->prepareLogicDefsFields($logicDefs, $name);
- $clientDefs['dynamicLogic']['fields'][$name]['invalid'] = null;
+ $logicDefs['fields'][$name]['invalid'] = null;
- $clientDefsToBeSet = true;
+ $logicDefsToBeSet = true;
}
}
}
- if ($clientDefsToBeSet) {
- $this->metadata->set('clientDefs', $scope, $clientDefs);
+ if ($logicDefsToBeSet) {
+ $this->metadata->set('logicDefs', $scope, $logicDefs);
$metadataToBeSaved = true;
}
@@ -424,41 +413,21 @@ class FieldManager
}
/**
- * @param array $clientDefs
- * @param string $name
+ * @param array $logicDefs
*/
- private function prepareClientDefsFieldsDynamicLogic(&$clientDefs, $name): void
+ private function prepareLogicDefsFields(array &$logicDefs, string $name): void
{
- if (!array_key_exists('dynamicLogic', $clientDefs)) {
- $clientDefs['dynamicLogic'] = [];
- }
-
- if (!array_key_exists('fields', $clientDefs['dynamicLogic'])) {
- $clientDefs['dynamicLogic']['fields'] = [];
- }
-
- if (!array_key_exists($name, $clientDefs['dynamicLogic']['fields'])) {
- $clientDefs['dynamicLogic']['fields'][$name] = [];
- }
+ $logicDefs['fields'] ??= [];
+ $logicDefs['fields'][$name] ??= [];
}
/**
- * @param array $clientDefs
- * @param string $name
+ * @param array $logicDefs
*/
- private function prepareClientDefsOptionsDynamicLogic(&$clientDefs, $name): void
+ private function prepareLogicDefsOptions(array &$logicDefs, string $name): void
{
- if (!array_key_exists('dynamicLogic', $clientDefs)) {
- $clientDefs['dynamicLogic'] = [];
- }
-
- if (!array_key_exists('options', $clientDefs['dynamicLogic'])) {
- $clientDefs['dynamicLogic']['options'] = [];
- }
-
- if (!array_key_exists($name, $clientDefs['dynamicLogic']['options'])) {
- $clientDefs['dynamicLogic']['options'][$name] = [];
- }
+ $logicDefs['options'] ??= [];
+ $logicDefs['options'][$name] ??= [];
}
/**
@@ -511,9 +480,9 @@ class FieldManager
$this->metadata->delete('entityDefs', $scope, $unsets);
- $this->metadata->delete('clientDefs', $scope, [
- "dynamicLogic.fields.$name",
- "dynamicLogic.options.$name",
+ $this->metadata->delete('logicDefs', $scope, [
+ "fields.$name",
+ "options.$name",
]);
$this->metadata->save();
@@ -558,9 +527,9 @@ class FieldManager
$this->metadata->delete('entityDefs', $scope, ['fields.' . $name]);
- $this->metadata->delete('clientDefs', $scope, [
- 'dynamicLogic.fields.' . $name,
- 'dynamicLogic.options.' . $name,
+ $this->metadata->delete('logicDefs', $scope, [
+ "fields.$name",
+ "options.$name",
]);
$this->metadata->save();
diff --git a/client/src/views/admin/field-manager/edit.js b/client/src/views/admin/field-manager/edit.js
index 2aa4c1f198..ffc2038b2d 100644
--- a/client/src/views/admin/field-manager/edit.js
+++ b/client/src/views/admin/field-manager/edit.js
@@ -451,8 +451,8 @@ class FieldManagerEditView extends View {
const promiseList = [];
if (!defs.dynamicLogicVisibleDisabled) {
- const isVisible = this.getMetadata()
- .get(['clientDefs', this.scope, 'dynamicLogic', 'fields', this.field, 'visible']);
+ const isVisible =
+ this.getMetadata().get(['logicDefs', this.scope, 'fields', this.field, 'visible']);
this.model.set(
'dynamicLogicVisible',
@@ -472,8 +472,8 @@ class FieldManagerEditView extends View {
const readOnly = this.getMetadata().get(['fields', this.type, 'readOnly']);
if (!defs.dynamicLogicRequiredDisabled && !readOnly && hasRequired) {
- const dynamicLogicRequired = this.getMetadata()
- .get(['clientDefs', this.scope, 'dynamicLogic', 'fields', this.field, 'required']);
+ const dynamicLogicRequired =
+ this.getMetadata().get(['logicDefs', this.scope, 'fields', this.field, 'required']);
this.model.set('dynamicLogicRequired', dynamicLogicRequired);
@@ -489,7 +489,7 @@ class FieldManagerEditView extends View {
if (!defs.dynamicLogicReadOnlyDisabled && !readOnly) {
const dynamicLogicReadOnly = this.getMetadata()
- .get(['clientDefs', this.scope, 'dynamicLogic', 'fields', this.field, 'readOnly']);
+ .get(['logicDefs', this.scope, 'fields', this.field, 'readOnly']);
this.model.set('dynamicLogicReadOnly', dynamicLogicReadOnly);
@@ -506,8 +506,8 @@ class FieldManagerEditView extends View {
const typeDynamicLogicOptions = this.getMetadata().get(['fields', this.type, 'dynamicLogicOptions']);
if (typeDynamicLogicOptions && !defs.dynamicLogicOptionsDisabled) {
- const dynamicLogicOptions = this.getMetadata()
- .get(['clientDefs', this.scope, 'dynamicLogic', 'options', this.field]);
+ const dynamicLogicOptions =
+ this.getMetadata().get(['logicDefs', this.scope, 'options', this.field]);
this.model.set('dynamicLogicOptions', dynamicLogicOptions);
@@ -522,8 +522,8 @@ class FieldManagerEditView extends View {
}
if (!defs.dynamicLogicInvalidDisabled && !readOnly) {
- const dynamicLogicInvalid = this.getMetadata()
- .get(['clientDefs', this.scope, 'dynamicLogic', 'fields', this.field, 'invalid']);
+ const dynamicLogicInvalid =
+ this.getMetadata().get(['logicDefs', this.scope, 'fields', this.field, 'invalid']);
this.model.set('dynamicLogicInvalid', dynamicLogicInvalid);
diff --git a/client/src/views/record/detail.js b/client/src/views/record/detail.js
index 3413ca2d92..170af961bd 100644
--- a/client/src/views/record/detail.js
+++ b/client/src/views/record/detail.js
@@ -2062,8 +2062,7 @@ class DetailRecordView extends BaseRecordView {
this.initDependency();
- const dynamicLogic = Espo.Utils.clone(
- this.getMetadata().get(['clientDefs', this.entityType, 'dynamicLogic']) || {});
+ const dynamicLogic = {...this.getMetadata().get(`logicDefs.${this.entityType}`, {})};
this.dynamicLogicDefs = _.extend(dynamicLogic, this.dynamicLogicDefs);
diff --git a/schema/metadata/app/export.json b/schema/metadata/app/export.json
index a05a6321c5..06e0469c68 100644
--- a/schema/metadata/app/export.json
+++ b/schema/metadata/app/export.json
@@ -68,7 +68,7 @@
"properties": {
"visible": {
"description": "Conditions making the parameter visible.",
- "$ref": "./../clientDefs.json#/definitions/dynamicLogicVisible"
+ "$ref": "./../logicDefs.json#/definitions/dynamicLogicVisible"
}
}
}
diff --git a/schema/metadata/authenticationMethods.json b/schema/metadata/authenticationMethods.json
index 088f74479f..513bfc9f92 100644
--- a/schema/metadata/authenticationMethods.json
+++ b/schema/metadata/authenticationMethods.json
@@ -80,16 +80,16 @@
"properties": {
"visible": {
"description": "Conditions making the field visible.",
- "$ref": "./clientDefs.json#/definitions/dynamicLogicVisible"
+ "$ref": "./logicDefs.json#/definitions/dynamicLogicVisible"
},
"required": {
- "$ref": "./clientDefs.json#/definitions/dynamicLogicRequired"
+ "$ref": "./logicDefs.json#/definitions/dynamicLogicRequired"
},
"readOnly": {
- "$ref": "./clientDefs.json#/definitions/dynamicLogicReadOnly"
+ "$ref": "./logicDefs.json#/definitions/dynamicLogicReadOnly"
},
"invalid": {
- "$ref": "./clientDefs.json#/definitions/dynamicLogicInvalid"
+ "$ref": "./logicDefs.json#/definitions/dynamicLogicInvalid"
}
}
}
diff --git a/schema/metadata/clientDefs.json b/schema/metadata/clientDefs.json
index 2d63defef3..7293d541dd 100644
--- a/schema/metadata/clientDefs.json
+++ b/schema/metadata/clientDefs.json
@@ -746,74 +746,6 @@
"isExpandedByDefault": {
"description": "Actual for category scopes (e.g. DocumentFolder). If true, then by default it will be in expanded mode.",
"type": "boolean"
- },
- "dynamicLogic": {
- "description": "Dynamic logic definitions making a form dynamic.",
- "type": "object",
- "properties": {
- "fields": {
- "type": "object",
- "description": "Fields.",
- "additionalProperties": {
- "type": "object",
- "description": "A field name.",
- "properties": {
- "visible": {
- "description": "Conditions making the field visible.",
- "$ref": "#/definitions/dynamicLogicVisible"
- },
- "required": {
- "$ref": "#/definitions/dynamicLogicRequired"
- },
- "readOnly": {
- "$ref": "#/definitions/dynamicLogicReadOnly"
- },
- "invalid": {
- "$ref": "#/definitions/dynamicLogicInvalid"
- }
- }
- }
- },
- "panels": {
- "type": "object",
- "description": "Panels.",
- "additionalProperties": {
- "type": "object",
- "description": "A panel name.",
- "properties": {
- "visible": {
- "description": "Conditions making the panel visible.",
- "$ref": "#/definitions/dynamicLogicVisible"
- }
- }
- }
- },
- "options": {
- "type": "object",
- "description": "Enum options.",
- "additionalProperties": {
- "type": "array",
- "description": "A field name.",
- "items": {
- "type": "object",
- "properties": {
- "optionList": {
- "type": "array",
- "items": {"type": "string"},
- "description": "Options."
- },
- "conditionGroup": {
- "type": "array",
- "description": "An AND where clause.",
- "items": {
- "$ref": "#/definitions/dynamicLogicItem"
- }
- }
- }
- }
- }
- }
- }
}
},
"definitions": {
@@ -910,216 +842,6 @@
}
}
},
- "dynamicLogicVisible": {
- "type": "object",
- "description": "Conditions making the element visible.",
- "properties": {
- "conditionGroup": {
- "description": "An AND where clause.",
- "type": "array",
- "items": {
- "$ref": "#/definitions/dynamicLogicItem"
- }
- }
- }
- },
- "dynamicLogicRequired": {
- "type": "object",
- "description": "Conditions making the field required.",
- "properties": {
- "conditionGroup": {
- "type": "array",
- "description": "An AND where clause.",
- "items": {
- "$ref": "#/definitions/dynamicLogicItem"
- }
- }
- }
- },
- "dynamicLogicReadOnly": {
- "type": "object",
- "description": "Conditions making the field read-only.",
- "properties": {
- "conditionGroup": {
- "type": "array",
- "description": "An AND where clause.",
- "items": {
- "$ref": "#/definitions/dynamicLogicItem"
- }
- }
- }
- },
- "dynamicLogicInvalid": {
- "type": "object",
- "description": "Conditions making the field invalid.",
- "properties": {
- "conditionGroup": {
- "type": "array",
- "description": "An AND where clause.",
- "items": {
- "$ref": "#/definitions/dynamicLogicItem"
- }
- }
- }
- },
- "dynamicLogicItem": {
- "type": "object",
- "description": "A logic node.",
- "anyOf": [
- {
- "if": {
- "properties": {
- "type": {
- "anyOf": [
- {"const": "and"},
- {"const": "or"}
- ]
- }
- }
- },
- "then": {
- "properties": {
- "value": {
- "type": "array",
- "description": "Sub-items.",
- "items": {
- "$ref": "#/definitions/dynamicLogicItem"
- }
- }
- },
- "required": ["type", "value"]
- }
- },
- {
- "if": {
- "properties": {
- "type": {
- "anyOf": [
- {"const": "not"}
- ]
- }
- }
- },
- "then": {
- "properties": {
- "value": {
- "type": "object",
- "$ref": "#/definitions/dynamicLogicItem"
- }
- },
- "required": ["type", "value"]
- }
- },
- {
- "if": {
- "properties": {
- "type": {
- "anyOf": [
- {"const": "equals"},
- {"const": "notEquals"},
- {"const": "greaterThan"},
- {"const": "lessThan"},
- {"const": "greaterThanOrEquals"},
- {"const": "lessThanOrEquals"},
- {"const": "isEmpty"},
- {"const": "isNotEmpty"},
- {"const": "isTrue"},
- {"const": "isFalse"},
- {"const": "in"},
- {"const": "notIn"},
- {"const": "isToday"},
- {"const": "inFuture"},
- {"const": "inPast"},
- {"const": "contains"},
- {"const": "notContains"},
- {"const": "has"},
- {"const": "notHas"},
- {"const": "startsWith"},
- {"const": "endsWith"},
- {"const": "matches"}
- ]
- }
- }
- },
- "then": {
- "properties": {
- "value": {
- "description": "A value.",
- "anyOf": [
- {"type": "string"},
- {"type": "boolean"},
- {"type": "integer"},
- {"type": "integer"},
- {"type": "number"},
- {"type": "null"},
- {
- "type": "array",
- "items": {"type": "string"}
- },
- {
- "type": "array",
- "items": {"type": "integer"}
- },
- {
- "type": "array",
- "items": {"type": "number"}
- }
- ]
- },
- "attribute": {
- "type": "string",
- "description": "An attribute."
- }
- },
- "required": ["type", "attribute"]
- }
- }
- ],
- "properties": {
- "type": {
- "description": "A type.",
- "enum": [
- "and",
- "or",
- "not",
- "equals",
- "notEquals",
- "greaterThan",
- "lessThan",
- "greaterThanOrEquals",
- "lessThanOrEquals",
- "isEmpty",
- "isNotEmpty",
- "isTrue",
- "isFalse",
- "in",
- "notIn",
- "isToday",
- "inFuture",
- "inPast",
- "contains",
- "notContains",
- "has",
- "notHas",
- "startsWith",
- "endsWith",
- "matches"
- ]
- },
- "data": {
- "type": "object",
- "description": "Additional data. Not used for logic.",
- "additionalProperties": true,
- "properties": {
- "field": {
- "type": "string",
- "description": "A field."
- }
- }
- }
- },
- "required": ["type"]
- },
"actionDefs": {
"type": "object",
"properties": {
diff --git a/schema/metadata/logicDefs.json b/schema/metadata/logicDefs.json
new file mode 100644
index 0000000000..0eb098702c
--- /dev/null
+++ b/schema/metadata/logicDefs.json
@@ -0,0 +1,282 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://www.espocrm.com/schema/metadata/clientDefs.json",
+ "title": "clientDefs",
+ "description": "Dynamic logic for entity types.",
+ "type": "object",
+ "properties": {
+ "fields": {
+ "type": "object",
+ "description": "Fields.",
+ "additionalProperties": {
+ "type": "object",
+ "description": "A field name.",
+ "properties": {
+ "visible": {
+ "$ref": "#/definitions/dynamicLogicVisible"
+ },
+ "required": {
+ "$ref": "#/definitions/dynamicLogicRequired"
+ },
+ "readOnly": {
+ "$ref": "#/definitions/dynamicLogicReadOnly"
+ },
+ "invalid": {
+ "$ref": "#/definitions/dynamicLogicInvalid"
+ }
+ }
+ }
+ },
+ "panels": {
+ "type": "object",
+ "description": "Panels.",
+ "additionalProperties": {
+ "type": "object",
+ "description": "A panel name.",
+ "properties": {
+ "visible": {
+ "description": "Conditions making the panel visible.",
+ "$ref": "#/definitions/dynamicLogicVisible"
+ }
+ }
+ }
+ },
+ "options": {
+ "type": "object",
+ "description": "Enum options.",
+ "additionalProperties": {
+ "type": "array",
+ "description": "A field name.",
+ "items": {
+ "type": "object",
+ "properties": {
+ "optionList": {
+ "type": "array",
+ "items": {"type": "string"},
+ "description": "Options."
+ },
+ "conditionGroup": {
+ "type": "array",
+ "description": "An AND where clause.",
+ "items": {
+ "$ref": "#/definitions/dynamicLogicItem"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "definitions": {
+ "dynamicLogicVisible": {
+ "type": "object",
+ "description": "Conditions making the element visible.",
+ "properties": {
+ "conditionGroup": {
+ "description": "An AND where clause.",
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/dynamicLogicItem"
+ }
+ }
+ }
+ },
+ "dynamicLogicRequired": {
+ "type": "object",
+ "description": "Conditions making the field required.",
+ "properties": {
+ "conditionGroup": {
+ "type": "array",
+ "description": "An AND where clause.",
+ "items": {
+ "$ref": "#/definitions/dynamicLogicItem"
+ }
+ }
+ }
+ },
+ "dynamicLogicReadOnly": {
+ "type": "object",
+ "description": "Conditions making the field read-only.",
+ "properties": {
+ "conditionGroup": {
+ "type": "array",
+ "description": "An AND where clause.",
+ "items": {
+ "$ref": "#/definitions/dynamicLogicItem"
+ }
+ }
+ }
+ },
+ "dynamicLogicInvalid": {
+ "type": "object",
+ "description": "Conditions making the field invalid.",
+ "properties": {
+ "conditionGroup": {
+ "type": "array",
+ "description": "An AND where clause.",
+ "items": {
+ "$ref": "#/definitions/dynamicLogicItem"
+ }
+ }
+ }
+ },
+ "dynamicLogicItem": {
+ "type": "object",
+ "description": "A logic node.",
+ "anyOf": [
+ {
+ "if": {
+ "properties": {
+ "type": {
+ "anyOf": [
+ {"const": "and"},
+ {"const": "or"}
+ ]
+ }
+ }
+ },
+ "then": {
+ "properties": {
+ "value": {
+ "type": "array",
+ "description": "Sub-items.",
+ "items": {
+ "$ref": "#/definitions/dynamicLogicItem"
+ }
+ }
+ },
+ "required": ["type", "value"]
+ }
+ },
+ {
+ "if": {
+ "properties": {
+ "type": {
+ "anyOf": [
+ {"const": "not"}
+ ]
+ }
+ }
+ },
+ "then": {
+ "properties": {
+ "value": {
+ "type": "object",
+ "$ref": "#/definitions/dynamicLogicItem"
+ }
+ },
+ "required": ["type", "value"]
+ }
+ },
+ {
+ "if": {
+ "properties": {
+ "type": {
+ "anyOf": [
+ {"const": "equals"},
+ {"const": "notEquals"},
+ {"const": "greaterThan"},
+ {"const": "lessThan"},
+ {"const": "greaterThanOrEquals"},
+ {"const": "lessThanOrEquals"},
+ {"const": "isEmpty"},
+ {"const": "isNotEmpty"},
+ {"const": "isTrue"},
+ {"const": "isFalse"},
+ {"const": "in"},
+ {"const": "notIn"},
+ {"const": "isToday"},
+ {"const": "inFuture"},
+ {"const": "inPast"},
+ {"const": "contains"},
+ {"const": "notContains"},
+ {"const": "has"},
+ {"const": "notHas"},
+ {"const": "startsWith"},
+ {"const": "endsWith"},
+ {"const": "matches"}
+ ]
+ }
+ }
+ },
+ "then": {
+ "properties": {
+ "value": {
+ "description": "A value.",
+ "anyOf": [
+ {"type": "string"},
+ {"type": "boolean"},
+ {"type": "integer"},
+ {"type": "integer"},
+ {"type": "number"},
+ {"type": "null"},
+ {
+ "type": "array",
+ "items": {"type": "string"}
+ },
+ {
+ "type": "array",
+ "items": {"type": "integer"}
+ },
+ {
+ "type": "array",
+ "items": {"type": "number"}
+ }
+ ]
+ },
+ "attribute": {
+ "type": "string",
+ "description": "An attribute."
+ }
+ },
+ "required": ["type", "attribute"]
+ }
+ }
+ ],
+ "properties": {
+ "type": {
+ "description": "A type.",
+ "enum": [
+ "and",
+ "or",
+ "not",
+ "equals",
+ "notEquals",
+ "greaterThan",
+ "lessThan",
+ "greaterThanOrEquals",
+ "lessThanOrEquals",
+ "isEmpty",
+ "isNotEmpty",
+ "isTrue",
+ "isFalse",
+ "in",
+ "notIn",
+ "isToday",
+ "inFuture",
+ "inPast",
+ "contains",
+ "notContains",
+ "has",
+ "notHas",
+ "startsWith",
+ "endsWith",
+ "matches"
+ ]
+ },
+ "data": {
+ "type": "object",
+ "description": "Additional data. Not used for logic.",
+ "additionalProperties": true,
+ "properties": {
+ "field": {
+ "type": "string",
+ "description": "A field."
+ }
+ }
+ }
+ },
+ "required": ["type"]
+ }
+ }
+}