enable collaborators for tasks and cases

This commit is contained in:
Yurii
2026-02-21 16:50:52 +02:00
parent 65d2c1de07
commit 39b461a618
8 changed files with 132 additions and 21 deletions

View File

@@ -33,6 +33,7 @@ use Espo\Core\Utils\DataUtil;
use Espo\Core\Utils\Metadata\AdditionalBuilder;
use Espo\Core\Utils\Metadata\BuilderHelper;
use Espo\Core\Utils\Util;
use RuntimeException;
use stdClass;
class Fields implements AdditionalBuilder
@@ -75,6 +76,10 @@ class Fields implements AdditionalBuilder
}
foreach (get_object_vars($entityDefsItem->fields) as $field => $fieldDefsItem) {
if (!is_object($fieldDefsItem)) {
throw new RuntimeException("Bad definition for $entityType.$field field.");
}
$additionalFields = $this->builderHelper->getAdditionalFields(
field: $field,
params: Util::objectToArray($fieldDefsItem),

View File

@@ -5,6 +5,9 @@
{
"name": "teams"
},
{
"name": "collaborators"
},
{
"name": "isInternal"
}

View File

@@ -122,6 +122,21 @@
"type": "linkMultiple",
"view": "views/fields/teams"
},
"collaborators": {
"type": "linkMultiple",
"view": "views/fields/collaborators",
"maxCount": 30,
"fieldManagerParamList": [
"readOnly",
"readOnlyAfterCreate",
"audited",
"autocompleteOnEmpty",
"maxCount",
"inlineEditDisabled",
"tooltipText"
],
"dynamicLogicVisibleDisabled": true
},
"attachments": {
"type": "attachmentMultiple"
}
@@ -145,6 +160,12 @@
"relationName": "entityTeam",
"layoutRelationshipsDisabled": true
},
"collaborators": {
"type": "hasMany",
"entity": "User",
"relationName": "entityCollaborator",
"layoutRelationshipsDisabled": true
},
"inboundEmail": {
"type": "belongsTo",
"entity": "InboundEmail"

View File

@@ -155,6 +155,21 @@
"type": "linkMultiple",
"view": "views/fields/teams"
},
"collaborators": {
"type": "linkMultiple",
"view": "views/fields/collaborators",
"maxCount": 30,
"fieldManagerParamList": [
"readOnly",
"readOnlyAfterCreate",
"audited",
"autocompleteOnEmpty",
"maxCount",
"inlineEditDisabled",
"tooltipText"
],
"dynamicLogicVisibleDisabled": true
},
"attachments": {
"type": "attachmentMultiple",
"sourceList": ["Document"]
@@ -180,6 +195,12 @@
"relationName": "entityTeam",
"layoutRelationshipsDisabled": true
},
"collaborators": {
"type": "hasMany",
"entity": "User",
"relationName": "entityCollaborator",
"layoutRelationshipsDisabled": true
},
"parent": {
"type": "belongsToParent",
"foreign": "tasks"

View File

@@ -17,5 +17,6 @@
"importable": true,
"notifications": true,
"object": true,
"statusField": "status"
"statusField": "status",
"collaborators": true
}

View File

@@ -19,5 +19,6 @@
"statusField": "status",
"stream": true,
"kanbanStatusIgnoreList": ["Canceled", "Deferred"],
"statusFieldLocked": true
"statusFieldLocked": true,
"collaborators": true
}

View File

@@ -112,4 +112,11 @@ class RelationParam
* @since 9.4.0
*/
public const READ_ONLY = 'readOnly';
/**
* Disabled.
*
* @since 9.4.0
*/
public const DISABLED = 'disabled';
}

View File

@@ -36,6 +36,8 @@ use Espo\Core\ORM\Type\FieldType;
use Espo\Core\Utils\Log;
use Espo\Core\Utils\Metadata;
use Espo\Entities\User;
use Espo\Modules\Crm\Entities\CaseObj;
use Espo\ORM\Defs\Params\FieldParam;
use Espo\ORM\Defs\Params\RelationParam;
use Espo\ORM\Type\RelationType;
use Espo\Tools\EntityManager\Hook\UpdateHook;
@@ -52,6 +54,13 @@ class CollaboratorsUpdateHook implements UpdateHook
private const DEFAULT_MAX_COUNT = 30;
/**
* @var string[]
*/
private array $enabledByDefaultEntityTypeList = [
CaseObj::ENTITY_TYPE,
];
public function __construct(
private Metadata $metadata,
private Log $log,
@@ -81,6 +90,59 @@ class CollaboratorsUpdateHook implements UpdateHook
return;
}
if ($this->isEnabledByDefault($entityType)) {
$this->addEnabledByDefault($entityType);
} else {
$this->addInternal($entityType);
}
$this->metadata->save();
$this->dataManager->rebuild([$entityType]);
}
private function remove(string $entityType): void
{
$field = self::FIELD;
if (
$this->metadata->get("entityDefs.$entityType.links.$field.isCustom") &&
$this->metadata->get("entityDefs.$entityType.links.$field.relationName") !== self::RELATION_NAME
) {
return;
}
$this->metadata->delete('entityDefs', $entityType, [
'fields.' . self::FIELD,
'links.' . self::FIELD,
]);
$this->metadata->delete('entityAcl', $entityType, [
'links.' . self::FIELD,
]);
$this->metadata->save();
// Must be after metadata is saved.
if ($this->isEnabledByDefault($entityType)) {
$this->metadata->set('entityDefs', $entityType, [
'fields' => [
self::FIELD => [
FieldParam::DISABLED => true,
],
],
'links' => [
self::FIELD => [
RelationParam::DISABLED => true,
],
],
]);
$this->metadata->save();
}
}
private function addInternal(string $entityType): void
{
$this->metadata->set('entityDefs', $entityType, [
'fields' => [
self::FIELD => [
@@ -116,32 +178,22 @@ class CollaboratorsUpdateHook implements UpdateHook
],
],
]);
$this->metadata->save();
$this->dataManager->rebuild([$entityType]);
}
private function remove(string $entityType): void
private function addEnabledByDefault(string $entityType): void
{
$field = self::FIELD;
if (
$this->metadata->get("entityDefs.$entityType.links.$field.isCustom") &&
$this->metadata->get("entityDefs.$entityType.links.$field.relationName") !== self::RELATION_NAME
) {
return;
}
$this->metadata->delete('entityDefs', $entityType, [
'fields.' . self::FIELD,
'links.' . self::FIELD,
]);
}
$this->metadata->delete('entityAcl', $entityType, [
'links.' . self::FIELD,
]);
$this->metadata->save();
/**
* @param string $entityType
* @return bool
*/
private function isEnabledByDefault(string $entityType): bool
{
return in_array($entityType, $this->enabledByDefaultEntityTypeList);
}
}