From a081237b2e54967d2b552a2008e6d1d45274d98b Mon Sep 17 00:00:00 2001 From: Yuri Kuznetsov Date: Sat, 20 Apr 2024 20:50:03 +0300 Subject: [PATCH] link multiple maxCount --- .../FieldValidators/LinkMultipleType.php | 35 ++++++++++++++----- .../metadata/fields/attachmentMultiple.json | 9 ++++- .../metadata/fields/linkMultiple.json | 25 ++++++++----- .../src/views/fields/attachment-multiple.js | 34 +++++++++++++++++- client/src/views/fields/link-multiple.js | 33 +++++++++++++++++ 5 files changed, 117 insertions(+), 19 deletions(-) diff --git a/application/Espo/Classes/FieldValidators/LinkMultipleType.php b/application/Espo/Classes/FieldValidators/LinkMultipleType.php index 2d920b8674..c9101a95b7 100644 --- a/application/Espo/Classes/FieldValidators/LinkMultipleType.php +++ b/application/Espo/Classes/FieldValidators/LinkMultipleType.php @@ -36,20 +36,17 @@ use Espo\Core\ORM\Entity as CoreEntity; use stdClass; +/** + * @noinspection PhpUnused + */ class LinkMultipleType { - private Metadata $metadata; - private Defs $defs; - private const COLUMN_TYPE_ENUM = 'enum'; private const COLUMN_TYPE_VARCHAR = 'varchar'; private const COLUMN_TYPE_BOOL = 'bool'; - public function __construct(Metadata $metadata, Defs $defs) - { - $this->metadata = $metadata; - $this->defs = $defs; - } + public function __construct(private Metadata $metadata, private Defs $defs) + {} public function checkRequired(Entity $entity, string $field): bool { @@ -63,6 +60,7 @@ class LinkMultipleType return count($idList) > 0; } + /** @noinspection PhpUnused */ public function checkPattern(Entity $entity, string $field): bool { /** @var ?mixed[] $idList */ @@ -93,6 +91,27 @@ class LinkMultipleType return true; } + /** @noinspection PhpUnused */ + public function checkMaxCount(Entity $entity, string $field, ?int $maxCount): bool + { + if ($maxCount === null) { + return true; + } + + $list = $entity->get($field . 'Ids'); + + if (!is_array($list)) { + return true; + } + + if (count($list) > $maxCount) { + return false; + } + + return true; + } + + /** @noinspection PhpUnused */ public function checkColumnsValid(Entity $entity, string $field): bool { if (!$entity instanceof CoreEntity) { diff --git a/application/Espo/Resources/metadata/fields/attachmentMultiple.json b/application/Espo/Resources/metadata/fields/attachmentMultiple.json index 00a6b6726a..403b5bdef2 100644 --- a/application/Espo/Resources/metadata/fields/attachmentMultiple.json +++ b/application/Espo/Resources/metadata/fields/attachmentMultiple.json @@ -54,6 +54,12 @@ ".txt" ], "tooltip": "fileAccept" + }, + { + "name": "maxCount", + "type": "int", + "min": 1, + "tooltip": true } ], "actualFields": [ @@ -77,7 +83,8 @@ "personalData": true, "validationList": [ "required", - "pattern" + "pattern", + "maxCount" ], "mandatoryValidationList": [ "pattern" diff --git a/application/Espo/Resources/metadata/fields/linkMultiple.json b/application/Espo/Resources/metadata/fields/linkMultiple.json index ab922ba77a..b9ef44945b 100644 --- a/application/Espo/Resources/metadata/fields/linkMultiple.json +++ b/application/Espo/Resources/metadata/fields/linkMultiple.json @@ -5,12 +5,6 @@ "type": "bool", "default": false }, - { - "name": "sortable", - "type": "bool", - "default": false, - "hidden": true - }, { "name": "readOnly", "type": "bool", @@ -20,6 +14,11 @@ "name": "readOnlyAfterCreate", "type": "bool" }, + { + "name": "audited", + "type": "bool", + "tooltip": true + }, { "name": "default", "type": "linkMultiple", @@ -34,9 +33,16 @@ "type": "bool" }, { - "name": "audited", - "type": "bool", + "name": "maxCount", + "type": "int", + "min": 1, "tooltip": true + }, + { + "name": "sortable", + "type": "bool", + "default": false, + "hidden": true } ], "actualFields": [ @@ -49,7 +55,8 @@ "validationList": [ "required", "pattern", - "columnsValid" + "columnsValid", + "maxCount" ], "mandatoryValidationList": [ "pattern", diff --git a/client/src/views/fields/attachment-multiple.js b/client/src/views/fields/attachment-multiple.js index f516e4c5f3..388ec921a9 100644 --- a/client/src/views/fields/attachment-multiple.js +++ b/client/src/views/fields/attachment-multiple.js @@ -55,6 +55,7 @@ class AttachmentMultipleFieldView extends BaseFieldView { * @property {string[]} [sourceList] A source list. * @property {string[]} [accept] Formats to accept. * @property {number} [maxFileSize] A max file size (in Mb). + * @property {number} [maxCount] A max number of items. */ /** @@ -81,7 +82,11 @@ class AttachmentMultipleFieldView extends BaseFieldView { foreignScope showPreviews = true accept = null - validations = ['ready', 'required'] + validations = [ + 'ready', + 'required', + 'maxCount', + ] searchTypeList = ['isNotEmpty', 'isEmpty'] events = { @@ -932,6 +937,33 @@ class AttachmentMultipleFieldView extends BaseFieldView { } } + // noinspection JSUnusedGlobalSymbols + validateMaxCount() { + const maxCount = this.params.maxCount; + + if (!maxCount) { + return false; + } + + const idList = this.model.get(this.idsName) || []; + + if (idList.length === 0) { + return false; + } + + if (idList.length <= maxCount) { + return false; + } + + const msg = this.translate('fieldExceedsMaxCount', 'messages') + .replace('{field}', this.getLabelText()) + .replace('{maxCount}', maxCount.toString()); + + this.showValidationMessage(msg, 'label'); + + return true; + } + fetch() { const data = {}; diff --git a/client/src/views/fields/link-multiple.js b/client/src/views/fields/link-multiple.js index f94377c0bd..4efa419a8f 100644 --- a/client/src/views/fields/link-multiple.js +++ b/client/src/views/fields/link-multiple.js @@ -54,6 +54,7 @@ class LinkMultipleFieldView extends BaseFieldView { * @property {boolean} [autocompleteOnEmpty] Autocomplete on empty input. * @property {boolean} [sortable] Sortable. * @property {boolean} [createButton] Show 'Create' button. + * @property {number} [maxCount] A max number of items. */ /** @@ -73,6 +74,11 @@ class LinkMultipleFieldView extends BaseFieldView { editTemplate = 'fields/link-multiple/edit' searchTemplate = 'fields/link-multiple/search' + validations = [ + 'required', + 'maxCount', + ] + /** * A name-hash attribute name. * @@ -831,6 +837,33 @@ class LinkMultipleFieldView extends BaseFieldView { return false; } + // noinspection JSUnusedGlobalSymbols + validateMaxCount() { + const maxCount = this.params.maxCount; + + if (!maxCount) { + return false; + } + + const idList = this.model.get(this.idsName) || []; + + if (idList.length === 0) { + return false; + } + + if (idList.length <= maxCount) { + return false; + } + + const msg = this.translate('fieldExceedsMaxCount', 'messages') + .replace('{field}', this.getLabelText()) + .replace('{maxCount}', maxCount.toString()); + + this.showValidationMessage(msg); + + return true; + } + /** @inheritDoc */ fetch() { const data = {};