diff --git a/application/Espo/Controllers/Layout.php b/application/Espo/Controllers/Layout.php index 891c68ebb5..2e9987a64a 100644 --- a/application/Espo/Controllers/Layout.php +++ b/application/Espo/Controllers/Layout.php @@ -30,62 +30,49 @@ namespace Espo\Controllers; use Espo\Core\Utils as Utils; -use \Espo\Core\Exceptions\NotFound; -use \Espo\Core\Exceptions\Error; -use \Espo\Core\Exceptions\Forbidden; -use \Espo\Core\Exceptions\BadRequest; +use Espo\Core\Exceptions\NotFound; +use Espo\Core\Exceptions\Error; +use Espo\Core\Exceptions\Forbidden; +use Espo\Core\Exceptions\BadRequest; class Layout extends \Espo\Core\Controllers\Base { - public function actionRead($params, $data) + public function getActionRead($params, $data) { - return $this->getServiceFactory()->create('Layout')->getForFrontend($params['scope'], $params['name']); + $scope = $params['scope'] ?? null; + $name = $params['name'] ?? null; + + return $this->getServiceFactory()->create('Layout')->getForFrontend($scope, $name); } - public function actionUpdate($params, $data, $request) + public function putActionUpdate($params, $data, $request) { - if (is_object($data)) { - $data = get_object_vars($data); - } + if (is_object($data)) $data = get_object_vars($data); - if (!$this->getUser()->isAdmin()) { - throw new Forbidden(); - } + if (!$this->getUser()->isAdmin()) throw new Forbidden(); - if (!$request->isPut() && !$request->isPatch()) { - throw new BadRequest(); - } + $scope = $params['scope'] ?? null; + $name = $params['name'] ?? null; + $setId = $params['setId'] ?? null; - $layoutManager = $this->getContainer()->get('layout'); - $layoutManager->set($data, $params['scope'], $params['name']); - $result = $layoutManager->save(); - - if ($result === false) { - throw new Error("Error while saving layout."); - } - - $this->getContainer()->get('dataManager')->updateCacheTimestamp(); - - return $layoutManager->get($params['scope'], $params['name']); - } - - public function actionPatch($params, $data, $request) - { - return $this->actionUpdate($params, $data, $request); + return $this->getServiceFactory()->create('Layout')->update($scope, $name, $setId, $data); } public function postActionResetToDefault($params, $data, $request) { - if (!$this->getUser()->isAdmin()) { - throw new Forbidden(); - } + if (!$this->getUser()->isAdmin()) throw new Forbidden(); - if (empty($data->scope) || empty($data->name)) { - throw new BadRequest(); - } + if (empty($data->scope) || empty($data->name)) throw new BadRequest(); - $this->getContainer()->get('dataManager')->updateCacheTimestamp(); + return $this->getServiceFactory()->create('Layout')->resetToDefault($data->scope, $data->name, $data->setId ?? null); + } - return $this->getContainer()->get('layout')->resetToDefault($data->scope, $data->name); + public function getActionGetOriginal($params, $data, $request) + { + if (!$this->getUser()->isAdmin()) throw new Forbidden(); + + return $this->getServiceFactory()->create('Layout')->getOriginal( + $request->get('scope'), $request->get('name'), $request->get('setId') + ); } } diff --git a/application/Espo/Controllers/LayoutSet.php b/application/Espo/Controllers/LayoutSet.php new file mode 100644 index 0000000000..b81bcfa309 --- /dev/null +++ b/application/Espo/Controllers/LayoutSet.php @@ -0,0 +1,42 @@ +getUser()->isAdmin()) { + throw new Forbidden(); + } + } +} diff --git a/application/Espo/Core/SelectManagers/Base.php b/application/Espo/Core/SelectManagers/Base.php index 62a51e7947..ab107de181 100644 --- a/application/Espo/Core/SelectManagers/Base.php +++ b/application/Espo/Core/SelectManagers/Base.php @@ -1863,6 +1863,7 @@ class Base $method = 'filter' . ucfirst($filter); if (method_exists($this, $method)) { $this->$method($result); + return; } else { $className = $this->getMetadata()->get(['entityDefs', $this->entityType, 'collection', 'filters', $filter, 'className']); if ($className) { @@ -1877,7 +1878,10 @@ class Base } $impl->applyFilter($this->entityType, $filter, $result, $this); } + return; } + + $result['whereClause'][] = ['id' => null]; } public function applyFilter(string $filter, array &$result) diff --git a/application/Espo/Core/Utils/Database/Orm/Fields/Currency.php b/application/Espo/Core/Utils/Database/Orm/Fields/Currency.php index 15c18777a7..758ed08faf 100644 --- a/application/Espo/Core/Utils/Database/Orm/Fields/Currency.php +++ b/application/Espo/Core/Utils/Database/Orm/Fields/Currency.php @@ -99,6 +99,7 @@ class Currency extends Base 'orderBy' => [ 'sql' => $converedFieldName . " {direction}", 'leftJoins' => $leftJoins, + 'additionalSelect' => ["{$alias}.rate"], ], 'attributeRole' => 'valueConverted', 'fieldType' => 'currency', @@ -107,6 +108,7 @@ class Currency extends Base $defs[$entityType]['fields'][$fieldName]['orderBy'] = [ 'sql' => $part . " * {$alias}.rate {direction}", 'leftJoins' => $leftJoins, + 'additionalSelect' => ["{$alias}.rate"], ]; } diff --git a/application/Espo/Entities/LayoutRecord.php b/application/Espo/Entities/LayoutRecord.php new file mode 100644 index 0000000000..07193e0cd1 --- /dev/null +++ b/application/Espo/Entities/LayoutRecord.php @@ -0,0 +1,34 @@ +colorList) / 128); - return $this->colorList[$index]; + $colorList = $this->getMetadata()->get(['app', 'avatars', 'colorList']) ?? $this->colorList; + + $index = intval($x * count($colorList) / 128); + return $colorList[$index]; } public function run() @@ -111,7 +113,7 @@ class Avatar extends Image $hash = $userId; $color = $this->getColor($userId); if ($hash === 'system') { - $color = $this->systemColor; + $color = $this->getMetadata()->get(['app', 'avatars', 'systemColor']) ?? $this->systemColor; } $imgContent = $identicon->getImageData($hash, $width, $color); @@ -120,6 +122,4 @@ class Avatar extends Image } } } - } - diff --git a/application/Espo/ORM/DB/Query/Base.php b/application/Espo/ORM/DB/Query/Base.php index 85f0d7e0ae..581e4fe547 100644 --- a/application/Espo/ORM/DB/Query/Base.php +++ b/application/Espo/ORM/DB/Query/Base.php @@ -308,6 +308,7 @@ abstract class Base if (empty($params['customJoin'])) { $params['customJoin'] = ''; } + $params['additionalSelect'] = $params['additionalSelect'] ?? []; $wherePart = $this->getWhere($entity, $whereClause, 'AND', $params); @@ -318,9 +319,29 @@ abstract class Base } if (empty($params['aggregation'])) { - $selectPart = $this->getSelect($entity, $params['select'], $params['distinct'], $params['skipTextColumns'], $params['maxTextColumnsLength'], $params); + $selectPart = $this->getSelect( + $entity, $params['select'], $params['distinct'], $params['skipTextColumns'], $params['maxTextColumnsLength'], $params + ); + $orderPart = $this->getOrder($entity, $params['orderBy'], $params['order'], $params); + if (!empty($params['extraAdditionalSelect'])) { + $extraSelect = []; + foreach ($params['extraAdditionalSelect'] as $item) { + if (!in_array($item, $params['select']) && !in_array($item, $params['additionalSelect'])) { + $extraSelect[] = $item; + } + } + if (count($extraSelect)) { + $extraSelectPart = $this->getSelect( + $entity, $extraSelect, false + ); + if ($extraSelectPart) { + $selectPart .= ', ' . $extraSelectPart; + } + } + } + if (!empty($params['additionalColumns']) && is_array($params['additionalColumns']) && !empty($params['relationName'])) { foreach ($params['additionalColumns'] as $column => $field) { $itemAlias = $this->sanitizeSelectAlias($field); @@ -955,6 +976,16 @@ abstract class Base $params['joins'][] = $j; } } + + if (!empty($fieldDefs[$type]['additionalSelect'])) { + $params['extraAdditionalSelect'] = $params['extraAdditionalSelect'] ?? []; + foreach ($fieldDefs[$type]['additionalSelect'] as $value) { + $value = str_replace('{alias}', $alias, $value); + if (!in_array($value, $params['extraAdditionalSelect'])) { + $params['extraAdditionalSelect'][] = $value; + } + } + } } return $part; diff --git a/application/Espo/Repositories/LayoutSet.php b/application/Espo/Repositories/LayoutSet.php new file mode 100644 index 0000000000..889356798e --- /dev/null +++ b/application/Espo/Repositories/LayoutSet.php @@ -0,0 +1,68 @@ +isNew() && $entity->has('layoutList')) { + $listBefore = $entity->getFetched('layoutList') ?? []; + $listNow = $entity->get('layoutList') ?? []; + + foreach ($listBefore as $name) { + if (!in_array($name, $listNow)) { + $layout = $this->getEntityManager()->getRepository('LayoutRecord')->where([ + 'layoutSetId' => $entity->id, + 'name' => $name, + ])->findOne(); + if ($layout) { + $this->getEntityManager()->removeEntity($layout); + } + } + } + } + } + + protected function afterRemove(Entity $entity, array $options = []) + { + $layoutList = $this->getEntityManager()->getRepository('LayoutRecord')->where([ + 'layoutSetId' => $entity->id, + ])->find(); + + foreach ($layoutList as $layout) { + $this->getEntityManager()->removeEntity($layout); + } + } +} diff --git a/application/Espo/Resources/i18n/en_US/Admin.json b/application/Espo/Resources/i18n/en_US/Admin.json index 2da479c703..1d171c4829 100644 --- a/application/Espo/Resources/i18n/en_US/Admin.json +++ b/application/Espo/Resources/i18n/en_US/Admin.json @@ -71,6 +71,7 @@ "Permissions": "Permissions", "Email Addresses": "Email Addresses", "Phone Numbers": "Phone Numbers", + "Layout Sets": "Layout Sets", "Success": "Success", "Fail": "Fail", "is recommended": "is recommended", @@ -262,6 +263,7 @@ "emailAddresses": "All emailes addresses stored in the system.", "phoneNumbers": "All phone numbers stored in the system.", "dashboardTemplates": "Deploy dashboards to users.", + "layoutSets": "Collections of layouts that can be assigned to teams & portals.", "pdfTemplates": "Templates for printing to PDF." }, "options": { diff --git a/application/Espo/Resources/i18n/en_US/Global.json b/application/Espo/Resources/i18n/en_US/Global.json index 8c7960eba1..f3c6883a5a 100644 --- a/application/Espo/Resources/i18n/en_US/Global.json +++ b/application/Espo/Resources/i18n/en_US/Global.json @@ -51,6 +51,7 @@ "ArrayValue": "Array Value", "DashboardTemplate": "Dashboard Template", "Currency": "Currency", + "LayoutSet": "Layout Set", "Webhook": "Webhook" }, "scopeNamesPlural": { @@ -94,6 +95,7 @@ "ArrayValue": "Array Values", "DashboardTemplate": "Dashboard Templates", "Currency": "Currency", + "LayoutSet": "Layout Sets", "Webhook": "Webhooks" }, "labels": { diff --git a/application/Espo/Resources/i18n/en_US/LayoutSet.json b/application/Espo/Resources/i18n/en_US/LayoutSet.json new file mode 100644 index 0000000000..e3349e4bdb --- /dev/null +++ b/application/Espo/Resources/i18n/en_US/LayoutSet.json @@ -0,0 +1,11 @@ +{ + "fields": { + "layoutList": "Layouts" + }, + "labels": { + "Create LayoutSet": "Create Layout Set", + "Edit Layouts": "Edit Layouts" + }, + "tooltips": { + } +} diff --git a/application/Espo/Resources/i18n/en_US/Portal.json b/application/Espo/Resources/i18n/en_US/Portal.json index b4c0f36fc0..69568d4a83 100644 --- a/application/Espo/Resources/i18n/en_US/Portal.json +++ b/application/Espo/Resources/i18n/en_US/Portal.json @@ -17,12 +17,14 @@ "timeZone": "Time Zone", "weekStart": "First Day of Week", "defaultCurrency": "Default Currency", + "layoutSet": "Layout Set", "customUrl": "Custom URL", "customId": "Custom ID" }, "links": { "users": "Users", "portalRoles": "Roles", + "layoutSet": "Layout Set", "notes": "Notes" }, "tooltips": { diff --git a/application/Espo/Resources/i18n/en_US/Team.json b/application/Espo/Resources/i18n/en_US/Team.json index f737aa2f5e..792e232c22 100644 --- a/application/Espo/Resources/i18n/en_US/Team.json +++ b/application/Espo/Resources/i18n/en_US/Team.json @@ -2,12 +2,14 @@ "fields": { "name": "Name", "roles": "Roles", + "layoutSet": "Layout Set", "positionList": "Position List" }, "links": { "users": "Users", "notes": "Notes", "roles": "Roles", + "layoutSet": "Layout Set", "inboundEmails": "Group Email Accounts" }, "tooltips": { diff --git a/application/Espo/Resources/layouts/LayoutSet/detail.json b/application/Espo/Resources/layouts/LayoutSet/detail.json new file mode 100644 index 0000000000..9f83b8fe73 --- /dev/null +++ b/application/Espo/Resources/layouts/LayoutSet/detail.json @@ -0,0 +1,17 @@ +[ + { + "label": "", + "rows": [ + [{"name": "name"}, false], + [ + {"name": "layoutList"}, + { + "name": "edit", + "customLabel": "", + "view": "views/layout-set/fields/edit", + "inlineEditDisabled": true + } + ] + ] + } +] diff --git a/application/Espo/Resources/layouts/LayoutSet/detailSmall.json b/application/Espo/Resources/layouts/LayoutSet/detailSmall.json new file mode 100644 index 0000000000..b119d9e328 --- /dev/null +++ b/application/Espo/Resources/layouts/LayoutSet/detailSmall.json @@ -0,0 +1,8 @@ +[ + { + "label": "", + "rows": [ + [{"name": "name"}] + ] + } +] diff --git a/application/Espo/Resources/layouts/LayoutSet/list.json b/application/Espo/Resources/layouts/LayoutSet/list.json new file mode 100644 index 0000000000..2ae42ee989 --- /dev/null +++ b/application/Espo/Resources/layouts/LayoutSet/list.json @@ -0,0 +1,3 @@ +[ + {"name":"name", "link": true} +] diff --git a/application/Espo/Resources/layouts/LayoutSet/relationships.json b/application/Espo/Resources/layouts/LayoutSet/relationships.json new file mode 100644 index 0000000000..9b3453caf9 --- /dev/null +++ b/application/Espo/Resources/layouts/LayoutSet/relationships.json @@ -0,0 +1,3 @@ +[ + "teams" +] diff --git a/application/Espo/Resources/layouts/Portal/detail.json b/application/Espo/Resources/layouts/Portal/detail.json index 690516b898..cb0fb341c7 100644 --- a/application/Espo/Resources/layouts/Portal/detail.json +++ b/application/Espo/Resources/layouts/Portal/detail.json @@ -20,6 +20,7 @@ "label": "User Interface", "rows": [ [{"name": "companyLogo"}, {"name": "theme"}], + [{"name": "layoutSet"}, false], [{"name": "tabList"}, {"name": "quickCreateList"}], [{"name": "dashboardLayout", "fullWidth": true}] ] diff --git a/application/Espo/Resources/layouts/Team/detail.json b/application/Espo/Resources/layouts/Team/detail.json index 63675851e7..f8888defaf 100644 --- a/application/Espo/Resources/layouts/Team/detail.json +++ b/application/Espo/Resources/layouts/Team/detail.json @@ -2,11 +2,16 @@ { "rows": [ [ - {"name": "name"} + {"name": "name"}, + false ], [ {"name": "roles"}, {"name": "positionList"} + ], + [ + {"name": "layoutSet"}, + false ] ] } diff --git a/application/Espo/Resources/metadata/app/adminPanel.json b/application/Espo/Resources/metadata/app/adminPanel.json index 63dfa905e6..acda6c07c6 100644 --- a/application/Espo/Resources/metadata/app/adminPanel.json +++ b/application/Espo/Resources/metadata/app/adminPanel.json @@ -257,6 +257,13 @@ "iconClass": "fas fa-th-large", "description": "dashboardTemplates" }, + { + "url": "#LayoutSet", + "label": "Layout Sets", + "iconClass": "fas fa-table", + "description": "layoutSets" + + }, { "url": "#Attachment", "label": "Attachments", diff --git a/application/Espo/Resources/metadata/clientDefs/LayoutSet.json b/application/Espo/Resources/metadata/clientDefs/LayoutSet.json new file mode 100644 index 0000000000..37e746e4be --- /dev/null +++ b/application/Espo/Resources/metadata/clientDefs/LayoutSet.json @@ -0,0 +1,12 @@ +{ + "controller": "controllers/layout-set", + "searchPanelDisabled": true, + "duplicateDisabled": true, + "relationshipPanels": { + "teams": { + "createDisabled": true, + "viewDisabled": true, + "rowActionsView": "views/record/row-actions/relationship-unlink-only" + } + } +} diff --git a/application/Espo/Resources/metadata/entityDefs/LayoutRecord.json b/application/Espo/Resources/metadata/entityDefs/LayoutRecord.json new file mode 100644 index 0000000000..845a741b7a --- /dev/null +++ b/application/Espo/Resources/metadata/entityDefs/LayoutRecord.json @@ -0,0 +1,25 @@ +{ + "fields": { + "name": { + "type": "varchar" + }, + "layoutSet": { + "type": "link" + }, + "data": { + "type": "jsonObject" + } + }, + "links": { + "layoutSet": { + "type": "belengsTo", + "entity": "LayoutSet", + "foreign": "layoutRecords" + } + }, + "indexes": { + "nameLayoutSetId": { + "columns": ["name", "layoutSetId"] + } + } +} diff --git a/application/Espo/Resources/metadata/entityDefs/LayoutSet.json b/application/Espo/Resources/metadata/entityDefs/LayoutSet.json new file mode 100644 index 0000000000..c7440379c4 --- /dev/null +++ b/application/Espo/Resources/metadata/entityDefs/LayoutSet.json @@ -0,0 +1,44 @@ +{ + "fields": { + "name": { + "type": "varchar", + "required": true, + "maxLength": 100, + "trim": true + }, + "layoutList": { + "type": "multiEnum", + "displayAsList": true, + "view": "views/layout-set/fields/layout-list" + }, + "createdAt": { + "type": "datetime", + "readOnly": true + }, + "modifiedAt": { + "type": "datetime", + "readOnly": true + } + }, + "links": { + "layoutRecords": { + "type": "hasMany", + "entity": "LayoutRecord", + "foreign": "layoutSet" + }, + "teams": { + "type": "hasMany", + "entity": "Team", + "foreign": "layoutSet" + }, + "portals": { + "type": "hasMany", + "entity": "Portal", + "foreign": "layoutSet" + } + }, + "collection": { + "orderBy": "name", + "order": "asc" + } +} diff --git a/application/Espo/Resources/metadata/entityDefs/Portal.json b/application/Espo/Resources/metadata/entityDefs/Portal.json index 02632096d2..c82c8d4feb 100644 --- a/application/Espo/Resources/metadata/entityDefs/Portal.json +++ b/application/Espo/Resources/metadata/entityDefs/Portal.json @@ -94,6 +94,9 @@ "customUrl": { "type": "url" }, + "layoutSet": { + "type": "link" + }, "modifiedAt": { "type": "datetime", "readOnly": true @@ -136,6 +139,11 @@ "type": "hasMany", "entity": "Note", "foreign": "portals" + }, + "layoutSet": { + "type": "belongsTo", + "entity": "LayoutSet", + "foreign": "portals" } }, "collection": { diff --git a/application/Espo/Resources/metadata/entityDefs/Team.json b/application/Espo/Resources/metadata/entityDefs/Team.json index 78e47398cd..4289babb34 100644 --- a/application/Espo/Resources/metadata/entityDefs/Team.json +++ b/application/Espo/Resources/metadata/entityDefs/Team.json @@ -18,6 +18,9 @@ "notStorable": true, "disabled": true }, + "layoutSet": { + "type": "link" + }, "createdAt": { "type": "datetime", "readOnly": true @@ -47,6 +50,11 @@ "type": "hasMany", "entity": "InboundEmail", "foreign": "teams" + }, + "layoutSet": { + "type": "belongsTo", + "entity": "LayoutSet", + "foreign": "teams" } }, "collection": { diff --git a/application/Espo/Resources/metadata/scopes/LayoutRecord.json b/application/Espo/Resources/metadata/scopes/LayoutRecord.json new file mode 100644 index 0000000000..39c96e7ac2 --- /dev/null +++ b/application/Espo/Resources/metadata/scopes/LayoutRecord.json @@ -0,0 +1,3 @@ +{ + "entity": true +} diff --git a/application/Espo/Resources/metadata/scopes/LayoutSet.json b/application/Espo/Resources/metadata/scopes/LayoutSet.json new file mode 100644 index 0000000000..39c96e7ac2 --- /dev/null +++ b/application/Espo/Resources/metadata/scopes/LayoutSet.json @@ -0,0 +1,3 @@ +{ + "entity": true +} diff --git a/application/Espo/Resources/routes.json b/application/Espo/Resources/routes.json index 33cca66201..c664ab2a38 100644 --- a/application/Espo/Resources/routes.json +++ b/application/Espo/Resources/routes.json @@ -157,8 +157,8 @@ } }, { - "route": "/:controller/layout/:name", - "method": "patch", + "route": "/:controller/layout/:name/:setId", + "method": "put", "params": { "controller": "Layout", "scope": ":controller" diff --git a/application/Espo/Services/Layout.php b/application/Espo/Services/Layout.php index 4c96e26bde..bd9ea6f097 100644 --- a/application/Espo/Services/Layout.php +++ b/application/Espo/Services/Layout.php @@ -30,6 +30,7 @@ namespace Espo\Services; use Espo\Core\Exceptions\NotFound; +use Espo\Core\Exceptions\Error; class Layout extends \Espo\Core\Services\Base { @@ -37,7 +38,10 @@ class Layout extends \Espo\Core\Services\Base { $this->addDependency('acl'); $this->addDependency('layout'); + $this->addDependency('entityManager'); $this->addDependency('metadata'); + $this->addDependency('dataManager'); + $this->addDependency('user'); } protected function getAcl() @@ -52,10 +56,53 @@ class Layout extends \Espo\Core\Services\Base public function getForFrontend(string $scope, string $name) { - $dataString = $this->getInjection('layout')->get($scope, $name); + $layoutSetId = null; + $data = null; + + $em = $this->getInjection('entityManager'); + $user = $this->getInjection('user'); + + if ($user->isPortal()) { + $portalId = $user->get('portalId'); + if ($portalId) { + $portal = $em->getRepository('Portal')->select(['layoutSetId'])->where(['id' => $portalId])->findOne(); + if ($portal) { + $layoutSetId = $portal->get('layoutSetId'); + } + } + } else { + $teamId = $user->get('defaultTeamId'); + if ($teamId) { + $team = $em->getRepository('Team')->select(['layoutSetId'])->where(['id' => $teamId])->findOne(); + if ($team) { + $layoutSetId = $team->get('layoutSetId'); + } + } + } + + if ($layoutSetId) { + $nameReal = $name; + + if ($user->isPortal()) { + if (substr($name, -6) === 'Portal') { + $nameReal = substr($name, 0, -6); + } + } + + $layout = $this->getRecordFromSet($scope, $nameReal, $layoutSetId, true); + if ($layout) { + $data = $layout->get('data'); + } + } + + if (!$data) { + $dataString = $this->getInjection('layout')->get($scope, $name); + } else { + $dataString = json_encode($data); + } if (!$dataString) { - throw new NotFound("Layout {$scope}:{$scope} is not found."); + throw new NotFound("Layout {$scope}:{$name} is not found."); } if (!$this->getUser()->isAdmin()) { @@ -80,4 +127,90 @@ class Layout extends \Espo\Core\Services\Base return $dataString; } + + protected function getRecordFromSet(string $scope, string $name, string $setId, bool $skipCheck = false) + { + $em = $this->getInjection('entityManager'); + $layoutSet = $em->getEntity('LayoutSet', $setId); + if (!$layoutSet) throw new NotFound(); + + $layoutList = $layoutSet->get('layoutList') ?? []; + + $fullName = $scope . '.' . $name; + + if (!in_array($fullName, $layoutList)) { + if ($skipCheck) return null; + throw new NotFound("Layout {$fullName} is no allowed in set."); + } + + $layout = $em->getRepository('LayoutRecord')->where([ + 'layoutSetId' => $setId, + 'name' => $fullName, + ])->findOne(); + + return $layout; + } + + public function update(string $scope, string $name, ?string $setId, $data) + { + if ($setId) { + $layout = $this->getRecordFromSet($scope, $name, $setId); + + $em = $this->getInjection('entityManager'); + + if (!$layout) { + $layout = $em->getEntity('LayoutRecord'); + $layout->set([ + 'layoutSetId' => $setId, + 'name' => $scope . '.' . $name, + ]); + } + + $layout->set('data', $data); + + $em->saveEntity($layout); + + return $layout->get('data'); + } + + $layoutManager = $this->getInjection('layout'); + + $layoutManager->set($data, $scope, $name); + $result = $layoutManager->save(); + + if ($result === false) throw new Error("Error while saving layout."); + + $this->getInjection('dataManager')->updateCacheTimestamp(); + + return $layoutManager->get($scope, $name); + } + + public function resetToDefault(string $scope, string $name, ?string $setId = null) + { + $this->getInjection('dataManager')->updateCacheTimestamp(); + + if ($setId) { + $layout = $this->getRecordFromSet($scope, $name, $setId); + if ($layout) { + $em = $this->getInjection('entityManager'); + $em->removeEntity($layout); + } + return $this->getInjection('layout')->get($scope, $name); + } + + return $this->getInjection('layout')->resetToDefault($scope, $name); + } + + public function getOriginal(string $scope, string $name, ?string $setId = null) + { + $this->getInjection('dataManager')->updateCacheTimestamp(); + + if ($setId) { + $layout = $this->getRecordFromSet($scope, $name, $setId, true); + if ($layout) { + return $layout->get('data'); + } + } + return $this->getInjection('layout')->get($scope, $name); + } } diff --git a/client/res/templates/admin/layouts/index.tpl b/client/res/templates/admin/layouts/index.tpl index b326a164d6..7231af5950 100644 --- a/client/res/templates/admin/layouts/index.tpl +++ b/client/res/templates/admin/layouts/index.tpl @@ -1,6 +1,4 @@ -