Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 64c933e365 | |||
| 32055f3d6e | |||
| 804acae44b | |||
| 6b3f37c00e | |||
| 4bdc4878cd | |||
| 625d2bc128 | |||
| 0af5bb1b4b | |||
| 7a0d59357c | |||
| adbb46d02c | |||
| ac3884179e | |||
| 7cf1af188d | |||
| 21b695e4ef | |||
| fbda66defc | |||
| beb4435ee0 | |||
| 6a4c78c1cb | |||
| dc7f5d8e66 | |||
| 872a4c2f2c | |||
| 8a5204bc4c | |||
| acbf6a1742 | |||
| b2d3d56a85 | |||
| 8b83fa640f |
+5
-4
@@ -381,7 +381,7 @@ module.exports = grunt => {
|
||||
});
|
||||
|
||||
grunt.registerTask('upgrade', () => {
|
||||
cp.execSync("node diff --all --vendor", {stdio: 'inherit'});
|
||||
cp.execSync("node diff --closest", {stdio: 'inherit'});
|
||||
});
|
||||
|
||||
grunt.registerTask('unit-tests-run', () => {
|
||||
@@ -396,7 +396,7 @@ module.exports = grunt => {
|
||||
cp.execSync("composer run-script setConfigParams", {stdio: 'ignore'});
|
||||
});
|
||||
|
||||
grunt.registerTask('zip', () => {
|
||||
grunt.registerTask('zip', function () { // Don't change to arrow-function.
|
||||
const archiver = require('archiver');
|
||||
|
||||
let resolve = this.async();
|
||||
@@ -425,8 +425,9 @@ module.exports = grunt => {
|
||||
|
||||
archive
|
||||
.directory(currentPath + '/build/' + folder, folder)
|
||||
.pipe(zipOutput)
|
||||
.finalize();
|
||||
.pipe(zipOutput);
|
||||
|
||||
archive.finalize();
|
||||
});
|
||||
|
||||
grunt.registerTask('npm-install', () => {
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2022 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Classes\FieldValidators\Attachment;
|
||||
|
||||
use Espo\Classes\FieldValidators\LinkParentType;
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class Related extends LinkParentType
|
||||
{
|
||||
public function checkValid(Entity $entity, string $field): bool
|
||||
{
|
||||
$typeValue = $entity->get($field . 'Type');
|
||||
|
||||
if ($typeValue === 'TemplateManager') {
|
||||
return true;
|
||||
}
|
||||
|
||||
return parent::checkValid($entity, $field);
|
||||
}
|
||||
}
|
||||
@@ -133,7 +133,8 @@ class Htmlizer
|
||||
string $template,
|
||||
?string $cacheId = null,
|
||||
?array $additionalData = null,
|
||||
bool $skipLinks = false
|
||||
bool $skipLinks = false,
|
||||
bool $skipInlineAttachmentHandling = false
|
||||
): string {
|
||||
|
||||
$template = str_replace('<tcpdf ', '', $template);
|
||||
@@ -188,9 +189,11 @@ class Htmlizer
|
||||
|
||||
$html = $renderer($data);
|
||||
|
||||
$html = str_replace('?entryPoint=attachment&', '?entryPoint=attachment&', $html);
|
||||
if (!$skipInlineAttachmentHandling) {
|
||||
$html = str_replace('?entryPoint=attachment&', '?entryPoint=attachment&', $html);
|
||||
}
|
||||
|
||||
if ($this->entityManager) {
|
||||
if (!$skipInlineAttachmentHandling && $this->entityManager) {
|
||||
/** @var string $html */
|
||||
$html = preg_replace_callback(
|
||||
'/\?entryPoint=attachment\&id=([A-Za-z0-9]*)/',
|
||||
|
||||
@@ -39,25 +39,16 @@ use LogicException;
|
||||
|
||||
class TemplateRenderer
|
||||
{
|
||||
/**
|
||||
* @var ?array<string,mixed>
|
||||
*/
|
||||
/** @var ?array<string,mixed> */
|
||||
private $data = null;
|
||||
|
||||
private ?User $user = null;
|
||||
|
||||
private ?Entity $entity = null;
|
||||
|
||||
private bool $skipRelations = false;
|
||||
|
||||
private bool $skipInlineAttachmentHandling = false;
|
||||
private bool $applyAcl = false;
|
||||
|
||||
private bool $useUserTimezone = false;
|
||||
|
||||
private HtmlizerFactory $htmlizerFactory;
|
||||
|
||||
private ApplicationState $applicationState;
|
||||
|
||||
private ?string $template = null;
|
||||
|
||||
public function __construct(HtmlizerFactory $htmlizerFactory, ApplicationState $applicationState)
|
||||
@@ -107,6 +98,12 @@ class TemplateRenderer
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setSkipInlineAttachmentHandling(bool $skipInlineAttachmentHandling = true): self
|
||||
{
|
||||
$this->skipInlineAttachmentHandling = $skipInlineAttachmentHandling;
|
||||
|
||||
return $this;
|
||||
}
|
||||
public function setApplyAcl(bool $applyAcl = true): self
|
||||
{
|
||||
$this->applyAcl = $applyAcl;
|
||||
@@ -149,7 +146,8 @@ class TemplateRenderer
|
||||
$template,
|
||||
null,
|
||||
$this->data,
|
||||
$this->skipRelations
|
||||
$this->skipRelations,
|
||||
$this->skipInlineAttachmentHandling
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -174,6 +174,7 @@ class Invitations
|
||||
$subjectTpl,
|
||||
'invitation-email-subject-' . $entity->getEntityType(),
|
||||
$data,
|
||||
true,
|
||||
true
|
||||
);
|
||||
|
||||
@@ -182,7 +183,8 @@ class Invitations
|
||||
$bodyTpl,
|
||||
'invitation-email-body-' . $entity->getEntityType(),
|
||||
$data,
|
||||
false
|
||||
false,
|
||||
true
|
||||
);
|
||||
|
||||
$email->set('subject', $subject);
|
||||
|
||||
@@ -22,7 +22,8 @@
|
||||
"related": {
|
||||
"type": "linkParent",
|
||||
"noLoad": true,
|
||||
"view": "views/attachment/fields/parent"
|
||||
"view": "views/attachment/fields/parent",
|
||||
"validatorClassName": "Espo\\Classes\\FieldValidators\\Attachment\\Related"
|
||||
},
|
||||
"sourceId": {
|
||||
"type": "varchar",
|
||||
|
||||
@@ -235,7 +235,6 @@
|
||||
},
|
||||
"language": {
|
||||
"type": "enum",
|
||||
"options": ["en_US"],
|
||||
"default": "en_US",
|
||||
"view": "views/settings/fields/language",
|
||||
"isSorted": true
|
||||
|
||||
@@ -158,7 +158,7 @@ class Attachment extends Record
|
||||
unset($data->parentId);
|
||||
unset($data->relatedId);
|
||||
|
||||
$isBeingUploaded = (bool) $data->isBeingUploaded;
|
||||
$isBeingUploaded = (bool) ($data->isBeingUploaded ?? false);
|
||||
|
||||
$contents = '';
|
||||
|
||||
@@ -283,6 +283,18 @@ class Attachment extends Record
|
||||
}
|
||||
}
|
||||
|
||||
private function getFieldType(AttachmentEntity $attachment): ?string
|
||||
{
|
||||
$field = $attachment->getTargetField();
|
||||
$entityType = $attachment->getParentType() ?? $attachment->getRelatedType();
|
||||
|
||||
if (!$field || !$entityType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->metadata->get(['entityDefs', $entityType, 'fields', $field, 'type']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Forbidden
|
||||
*/
|
||||
@@ -295,10 +307,8 @@ class Attachment extends Record
|
||||
return;
|
||||
}
|
||||
|
||||
$fieldType = $this->metadata->get(['entityDefs', $entityType, 'fields', $field, 'type']);
|
||||
|
||||
if (
|
||||
$fieldType === self::FIELD_TYPE_IMAGE ||
|
||||
$this->getFieldType($attachment) === self::FIELD_TYPE_IMAGE ||
|
||||
$attachment->getRole() === AttachmentEntity::ROLE_INLINE_ATTACHMENT
|
||||
) {
|
||||
$this->checkAttachmentTypeImage($attachment);
|
||||
@@ -306,7 +316,7 @@ class Attachment extends Record
|
||||
return;
|
||||
}
|
||||
|
||||
$extension = self::getFileExtension($attachment) ?? '';
|
||||
$extension = strtolower(self::getFileExtension($attachment) ?? '');
|
||||
|
||||
$mimeType = $this->getMimeTypeUtil()->getMimeTypeByExtension($extension) ??
|
||||
$attachment->getType();
|
||||
@@ -759,13 +769,15 @@ class Attachment extends Record
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->checkAttachmentTypeImage($attachment, $filePath);
|
||||
}
|
||||
catch (Forbidden $e) {
|
||||
$this->entityManager->removeEntity($attachment);
|
||||
if ($this->getFieldType($attachment) === self::FIELD_TYPE_IMAGE) {
|
||||
try {
|
||||
$this->checkAttachmentTypeImage($attachment, $filePath);
|
||||
}
|
||||
catch (Forbidden $e) {
|
||||
$this->entityManager->removeEntity($attachment);
|
||||
|
||||
throw new ForbiddenSilent($e->getMessage());
|
||||
throw new ForbiddenSilent($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
$attachment->set('isBeingUploaded', false);
|
||||
|
||||
@@ -2,16 +2,16 @@
|
||||
<h4>{{{title}}}</h4>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="button-container">
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-primary" data-action="save">{{translate 'Save'}}</button>
|
||||
<button class="btn btn-default" data-action="cancel">{{translate 'Cancel'}}</button>
|
||||
<button class="btn btn-default" data-action="resetToDefault">{{translate 'Reset to Default' scope='Admin'}}</button>
|
||||
<button class="btn btn-primary btn-xs-wide" data-action="save">{{translate 'Save'}}</button>
|
||||
<button class="btn btn-default btn-xs-wide" data-action="cancel">{{translate 'Cancel'}}</button>
|
||||
<button class="btn btn-default btn-xs-wide" data-action="resetToDefault"
|
||||
>{{translate 'Reset to Default' scope='Admin'}}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#if hasSubject}}
|
||||
<div class="subject-field">{{{subjectField}}}</div>
|
||||
{{/if}}
|
||||
<div class="body-field">{{{bodyField}}}</div>
|
||||
<div class="body-field">{{{bodyField}}}</div>
|
||||
|
||||
@@ -739,7 +739,7 @@ define('views/admin/entity-manager/edit', ['view', 'model'], function (Dep, Mode
|
||||
|
||||
if (
|
||||
this.getMetadata()
|
||||
.get(['entityDefs', foreignEntityType, 'fields', item, 'foreingAccessDisabled'])
|
||||
.get(['entityDefs', foreignEntityType, 'fields', item, 'foreignAccessDisabled'])
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -254,23 +254,35 @@ define('views/admin/layouts/bottom-panels-detail', ['views/admin/layouts/side-pa
|
||||
},
|
||||
|
||||
onDrop: function () {
|
||||
let tabBreakIndex = 0;
|
||||
let tabBreakIndex = -1;
|
||||
|
||||
let $tabBreak = null;
|
||||
|
||||
this.$el.find('ul.enabled').children().each((i, li) => {
|
||||
let $li = $(li);
|
||||
|
||||
let name = $li.attr('data-name');
|
||||
|
||||
if (this.isTabName(name)) {
|
||||
if (name === this.TAB_BREAK_KEY) {
|
||||
$tabBreak = $li.clone();
|
||||
if (name !== this.TAB_BREAK_KEY) {
|
||||
let itemIndex = parseInt(name.split('_')[2]);
|
||||
|
||||
$li.attr('data-name', this.TAB_BREAK_KEY.slice(0, -3) + tabBreakIndex);
|
||||
if (itemIndex > tabBreakIndex) {
|
||||
tabBreakIndex = itemIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
tabBreakIndex++;
|
||||
tabBreakIndex++;
|
||||
|
||||
this.$el.find('ul.enabled').children().each((i, li) => {
|
||||
let $li = $(li);
|
||||
let name = $li.attr('data-name');
|
||||
|
||||
if (this.isTabName(name) && name === this.TAB_BREAK_KEY) {
|
||||
$tabBreak = $li.clone();
|
||||
|
||||
$li.attr('data-name', this.TAB_BREAK_KEY.slice(0, -3) + tabBreakIndex);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -326,9 +338,11 @@ define('views/admin/layouts/bottom-panels-detail', ['views/admin/layouts/side-pa
|
||||
|
||||
newLayout[name] = layout[name];
|
||||
|
||||
if (this.isTabName(name) && this.itemsData[name]) {
|
||||
if (this.isTabName(name) && name !== this.TAB_BREAK_KEY /*&& this.itemsData[name]*/) {
|
||||
let data = this.itemsData[name] || {};
|
||||
|
||||
newLayout[name].tabBreak = true;
|
||||
newLayout[name].tabLabel = this.itemsData[name].tabLabel;
|
||||
newLayout[name].tabLabel = data.tabLabel;
|
||||
}
|
||||
else {
|
||||
delete newLayout[name].tabBreak;
|
||||
|
||||
@@ -343,7 +343,7 @@ function (Dep, FileUpload) {
|
||||
|
||||
getEditPreview: function (name, type, id) {
|
||||
if (!~this.previewTypeList.indexOf(type)) {
|
||||
return name;
|
||||
return null;
|
||||
}
|
||||
|
||||
return $('<img>')
|
||||
@@ -368,11 +368,9 @@ function (Dep, FileUpload) {
|
||||
if (this.showPreviews) {
|
||||
let html = this.getEditPreview(name, type, id);
|
||||
|
||||
if (!html) {
|
||||
return $text.get(0).outerHTML;
|
||||
if (html) {
|
||||
return html;
|
||||
}
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
let url = this.getBasePath() + '?entryPoint=download&id=' + id;
|
||||
|
||||
@@ -627,11 +627,9 @@ define('views/fields/file', ['views/fields/link', 'helpers/file-upload'], functi
|
||||
if (this.showPreview) {
|
||||
let html = this.getEditPreview(name, type, id);
|
||||
|
||||
if (!html) {
|
||||
return $text.get(0).outerHTML;
|
||||
if (html) {
|
||||
return html;
|
||||
}
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
let url = this.getBasePath() + '?entryPoint=download&id=' + id;
|
||||
|
||||
@@ -1063,7 +1063,7 @@ function (Dep, ViewRecordHelper, ActionItemSetup) {
|
||||
}
|
||||
|
||||
for (let i = 0; i < this.panelSoftLockedTypeList.length; i++) {
|
||||
var iType = this.panelSoftLockedTypeList[i];
|
||||
let iType = this.panelSoftLockedTypeList[i];
|
||||
|
||||
if (iType === softLockedType) {
|
||||
continue;
|
||||
@@ -1076,13 +1076,13 @@ function (Dep, ViewRecordHelper, ActionItemSetup) {
|
||||
}
|
||||
}
|
||||
|
||||
var middleView = this.getView('middle');
|
||||
let middleView = this.getView('middle');
|
||||
|
||||
if (middleView) {
|
||||
middleView.showPanelInternal(name);
|
||||
}
|
||||
|
||||
var bottomView = this.getView('bottom');
|
||||
let bottomView = this.getView('bottom');
|
||||
|
||||
if (bottomView) {
|
||||
if ('showPanel' in bottomView) {
|
||||
@@ -1090,16 +1090,24 @@ function (Dep, ViewRecordHelper, ActionItemSetup) {
|
||||
}
|
||||
}
|
||||
else if (this.bottomView) {
|
||||
this.once('after:render', () => {
|
||||
var bottomView = this.getView('bottom');
|
||||
this.once('ready', () => {
|
||||
let view = this.getView('bottom');
|
||||
|
||||
if (bottomView && 'showPanel' in bottomView) {
|
||||
bottomView.showPanel(name);
|
||||
if (view) {
|
||||
if ('processShowPanel' in view) {
|
||||
view.processShowPanel(name);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ('showPanel' in view) {
|
||||
view.showPanel(name);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var sideView = this.getView('side');
|
||||
let sideView = this.getView('side');
|
||||
|
||||
if (sideView) {
|
||||
if ('showPanel' in sideView) {
|
||||
@@ -1107,11 +1115,19 @@ function (Dep, ViewRecordHelper, ActionItemSetup) {
|
||||
}
|
||||
}
|
||||
else if (this.sideView) {
|
||||
this.once('after:render', () => {
|
||||
var sideView = this.getView('side');
|
||||
this.once('ready', () => {
|
||||
let view = this.getView('side');
|
||||
|
||||
if (sideView && 'showPanel' in sideView) {
|
||||
sideView.showPanel(name);
|
||||
if (view) {
|
||||
if ('processShowPanel' in view) {
|
||||
view.processShowPanel(name);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ('showPanel' in view) {
|
||||
view.showPanel(name);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1154,13 +1170,13 @@ function (Dep, ViewRecordHelper, ActionItemSetup) {
|
||||
}
|
||||
}
|
||||
|
||||
var middleView = this.getView('middle');
|
||||
let middleView = this.getView('middle');
|
||||
|
||||
if (middleView) {
|
||||
middleView.hidePanelInternal(name);
|
||||
}
|
||||
|
||||
var bottomView = this.getView('bottom');
|
||||
let bottomView = this.getView('bottom');
|
||||
|
||||
if (bottomView) {
|
||||
if ('hidePanel' in bottomView) {
|
||||
@@ -1168,16 +1184,24 @@ function (Dep, ViewRecordHelper, ActionItemSetup) {
|
||||
}
|
||||
}
|
||||
else if (this.bottomView) {
|
||||
this.once('after:render', () => {
|
||||
var bottomView = this.getView('bottom');
|
||||
this.once('ready', () => {
|
||||
let view = this.getView('bottom');
|
||||
|
||||
if (bottomView && 'showPanel' in bottomView) {
|
||||
bottomView.hidePanel(name);
|
||||
if (view) {
|
||||
if ('processHidePanel' in view) {
|
||||
view.processHidePanel(name);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ('hidePanel' in view) {
|
||||
view.hidePanel(name);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var sideView = this.getView('side');
|
||||
let sideView = this.getView('side');
|
||||
|
||||
if (sideView) {
|
||||
if ('hidePanel' in sideView) {
|
||||
@@ -1185,18 +1209,25 @@ function (Dep, ViewRecordHelper, ActionItemSetup) {
|
||||
}
|
||||
}
|
||||
else if (this.sideView) {
|
||||
this.once('after:render', () => {
|
||||
var sideView = this.getView('side');
|
||||
this.once('ready', () => {
|
||||
let view = this.getView('side');
|
||||
|
||||
if (sideView && 'hidePanel' in sideView) {
|
||||
sideView.hidePanel(name);
|
||||
if (view) {
|
||||
if ('processHidePanel' in view) {
|
||||
view.processHidePanel(name);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ('hidePanel' in view) {
|
||||
view.hidePanel(name);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.recordHelper.setPanelStateParam(name, 'hidden', true);
|
||||
|
||||
|
||||
if (this.middlePanelDefs[name]) {
|
||||
this.controlMiddleTabVisibilityHide(this.middlePanelDefs[name].tabNumber);
|
||||
|
||||
|
||||
@@ -394,52 +394,57 @@ define('views/record/panels-container', ['view'], function (Dep) {
|
||||
return data;
|
||||
},
|
||||
|
||||
showPanel: function (name, softLockedType, callback) {
|
||||
if (this.recordHelper.getPanelStateParam(name, 'hiddenLocked')) {
|
||||
/**
|
||||
* @param {string} name
|
||||
* @return {boolean}
|
||||
*/
|
||||
hasPanel: function (name) {
|
||||
return !!this.panelList.find(item => item.name === name);
|
||||
},
|
||||
|
||||
processShowPanel: function (name, callback, wasShown) {
|
||||
if (this.recordHelper.getPanelStateParam(name, 'hidden')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (softLockedType) {
|
||||
this.recordHelper
|
||||
.setPanelStateParam(name, 'hidden' + Espo.Utils.upperCaseFirst(softLockedType) + 'Locked',
|
||||
false);
|
||||
if (!this.hasPanel(name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < this.panelSoftLockedTypeList.length; i++) {
|
||||
var iType = this.panelSoftLockedTypeList[i];
|
||||
this.panelList.filter(item => item.name === name).forEach(item => {
|
||||
item.hidden = false;
|
||||
|
||||
if (iType === softLockedType) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var iParam = 'hidden' + Espo.Utils.upperCaseFirst(iType) + 'Locked';
|
||||
|
||||
if (this.recordHelper.getPanelStateParam(name, iParam)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let wasShown = this.recordHelper.getPanelStateParam(name, 'hidden') === false;
|
||||
|
||||
this.recordHelper.setPanelStateParam(name, 'hidden', false);
|
||||
|
||||
var isFound = false;
|
||||
|
||||
this.panelList.forEach(d => {
|
||||
if (d.name === name) {
|
||||
d.hidden = false;
|
||||
isFound = true;
|
||||
|
||||
this.controlTabVisibilityShow(d.tabNumber);
|
||||
if (typeof item.tabNumber !== 'undefined') {
|
||||
this.controlTabVisibilityShow(item.tabNumber);
|
||||
}
|
||||
});
|
||||
|
||||
if (!isFound) {
|
||||
this.showPanelFinalize(name, callback, wasShown);
|
||||
},
|
||||
|
||||
processHidePanel: function (name, callback) {
|
||||
if (!this.recordHelper.getPanelStateParam(name, 'hidden')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.hasPanel(name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.panelList.filter(item => item.name === name).forEach(item => {
|
||||
item.hidden = true;
|
||||
|
||||
if (typeof item.tabNumber !== 'undefined') {
|
||||
this.controlTabVisibilityHide(item.tabNumber);
|
||||
}
|
||||
});
|
||||
|
||||
this.hidePanelFinalize(name, callback);
|
||||
},
|
||||
|
||||
showPanelFinalize: function (name, callback, wasShown) {
|
||||
if (this.isRendered()) {
|
||||
var view = this.getView(name);
|
||||
let view = this.getView(name);
|
||||
|
||||
if (view) {
|
||||
view.$el.closest('.panel').removeClass('hidden');
|
||||
@@ -448,7 +453,7 @@ define('views/record/panels-container', ['view'], function (Dep) {
|
||||
view.trigger('show');
|
||||
|
||||
if (!wasShown && view.getFieldViews) {
|
||||
var fields = view.getFieldViews();
|
||||
let fields = view.getFieldViews();
|
||||
|
||||
if (fields) {
|
||||
for (let i in fields) {
|
||||
@@ -482,38 +487,9 @@ define('views/record/panels-container', ['view'], function (Dep) {
|
||||
});
|
||||
},
|
||||
|
||||
hidePanel: function (name, locked, softLockedType, callback) {
|
||||
this.recordHelper.setPanelStateParam(name, 'hidden', true);
|
||||
|
||||
if (locked) {
|
||||
this.recordHelper.setPanelStateParam(name, 'hiddenLocked', true);
|
||||
}
|
||||
|
||||
if (softLockedType) {
|
||||
this.recordHelper.setPanelStateParam(
|
||||
name,
|
||||
'hidden' + Espo.Utils.upperCaseFirst(softLockedType) + 'Locked',
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
var isFound = false;
|
||||
|
||||
this.panelList.forEach(d => {
|
||||
if (d.name === name) {
|
||||
d.hidden = true;
|
||||
isFound = true;
|
||||
|
||||
this.controlTabVisibilityHide(d.tabNumber);
|
||||
}
|
||||
});
|
||||
|
||||
if (!isFound) {
|
||||
return;
|
||||
}
|
||||
|
||||
hidePanelFinalize: function (name, callback) {
|
||||
if (this.isRendered()) {
|
||||
var view = this.getView(name);
|
||||
let view = this.getView(name);
|
||||
|
||||
if (view) {
|
||||
view.$el.closest('.panel').addClass('hidden');
|
||||
@@ -537,6 +513,62 @@ define('views/record/panels-container', ['view'], function (Dep) {
|
||||
}
|
||||
},
|
||||
|
||||
showPanel: function (name, softLockedType, callback) {
|
||||
if (!this.hasPanel(name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.recordHelper.getPanelStateParam(name, 'hiddenLocked')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (softLockedType) {
|
||||
let param = 'hidden' + Espo.Utils.upperCaseFirst(softLockedType) + 'Locked';
|
||||
|
||||
this.recordHelper.setPanelStateParam(name, param, false);
|
||||
|
||||
for (let i = 0; i < this.panelSoftLockedTypeList.length; i++) {
|
||||
let iType = this.panelSoftLockedTypeList[i];
|
||||
|
||||
if (iType === softLockedType) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let iParam = 'hidden' + Espo.Utils.upperCaseFirst(iType) + 'Locked';
|
||||
|
||||
if (this.recordHelper.getPanelStateParam(name, iParam)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let wasShown = this.recordHelper.getPanelStateParam(name, 'hidden') === false;
|
||||
|
||||
this.recordHelper.setPanelStateParam(name, 'hidden', false);
|
||||
|
||||
this.processShowPanel(name, callback, wasShown);
|
||||
},
|
||||
|
||||
hidePanel: function (name, locked, softLockedType, callback) {
|
||||
if (!this.hasPanel(name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.recordHelper.setPanelStateParam(name, 'hidden', true);
|
||||
|
||||
if (locked) {
|
||||
this.recordHelper.setPanelStateParam(name, 'hiddenLocked', true);
|
||||
}
|
||||
|
||||
if (softLockedType) {
|
||||
let param = 'hidden' + Espo.Utils.upperCaseFirst(softLockedType) + 'Locked';
|
||||
|
||||
this.recordHelper.setPanelStateParam(name, param, true);
|
||||
}
|
||||
|
||||
this.processHidePanel(name, callback);
|
||||
},
|
||||
|
||||
alterPanels: function (layoutData) {
|
||||
layoutData = layoutData || this.layoutData || {};
|
||||
|
||||
@@ -749,6 +781,26 @@ define('views/record/panels-container', ['view'], function (Dep) {
|
||||
this.$el.find(`.panel[data-tab="${tab}"]`).removeClass('tab-hidden');
|
||||
|
||||
this.adjustPanels();
|
||||
|
||||
this.panelList
|
||||
.filter(item => item.tabNumber === tab && item.name)
|
||||
.forEach(item => {
|
||||
let view = this.getView(item.name);
|
||||
|
||||
if (view) {
|
||||
view.trigger('tab-show');
|
||||
}
|
||||
});
|
||||
|
||||
this.panelList
|
||||
.filter(item => item.tabNumber !== tab && item.name)
|
||||
.forEach(item => {
|
||||
let view = this.getView(item.name);
|
||||
|
||||
if (view) {
|
||||
view.trigger('tab-hide');
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -344,5 +344,28 @@ define('views/record/panels/bottom', ['view'], function (Dep) {
|
||||
|
||||
this.createView(viewKey, viewName, o);
|
||||
},
|
||||
|
||||
/**
|
||||
* Is tab-hidden.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
isTabHidden: function () {
|
||||
if (this.defs.tabNumber === -1 || typeof this.defs.tabNumber === 'undefined') {
|
||||
return false;
|
||||
}
|
||||
|
||||
let parentView = this.getParentView();
|
||||
|
||||
if (!parentView) {
|
||||
return this.defs.tabNumber > 0;
|
||||
}
|
||||
|
||||
if (parentView && parentView.hasTabs) {
|
||||
return parentView.currentTab !== defs.tabNumber;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -384,5 +384,28 @@ define('views/record/panels/side', ['view'], function (Dep) {
|
||||
actionRefresh: function () {
|
||||
this.model.fetch();
|
||||
},
|
||||
|
||||
/**
|
||||
* Is tab-hidden.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
isTabHidden: function () {
|
||||
if (this.defs.tabNumber === -1 || typeof this.defs.tabNumber === 'undefined') {
|
||||
return false;
|
||||
}
|
||||
|
||||
let parentView = this.getParentView();
|
||||
|
||||
if (!parentView) {
|
||||
return this.defs.tabNumber > 0;
|
||||
}
|
||||
|
||||
if (parentView && parentView.hasTabs) {
|
||||
return parentView.currentTab !== defs.tabNumber;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -37,6 +37,7 @@ define('views/stream/notes/relate', ['views/stream/note'], function (Dep) {
|
||||
data: function () {
|
||||
return _.extend({
|
||||
relatedTypeString: this.translateEntityType(this.entityType),
|
||||
iconHtml: this.getIconHtml(this.entityType, this.entityId),
|
||||
}, Dep.prototype.data.call(this));
|
||||
},
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ let isDev = false;
|
||||
let isAll = false;
|
||||
let withVendor = true;
|
||||
let forceScripts = false;
|
||||
let isClosest = false;
|
||||
|
||||
if (process.argv.length > 1) {
|
||||
for (let i in process.argv) {
|
||||
@@ -67,6 +68,10 @@ if (process.argv.length > 1) {
|
||||
forceScripts = true;
|
||||
}
|
||||
|
||||
if (process.argv[i] === '--closest') {
|
||||
isClosest = true;
|
||||
}
|
||||
|
||||
if (~process.argv[i].indexOf('--acceptedVersion=')) {
|
||||
acceptedVersionName = process.argv[i].substr(('--acceptedVersion=').length);
|
||||
}
|
||||
@@ -75,22 +80,33 @@ if (process.argv.length > 1) {
|
||||
|
||||
let espoPath = path.dirname(fs.realpathSync(__filename));
|
||||
|
||||
if (isAll || isClosest) {
|
||||
acceptedVersionName = null;
|
||||
}
|
||||
|
||||
let diff = new Diff(espoPath, {
|
||||
isAll: isAll,
|
||||
isDev: isDev,
|
||||
withVendor: withVendor,
|
||||
forceScripts: forceScripts,
|
||||
acceptedVersionName: !isAll ? acceptedVersionName : null,
|
||||
acceptedVersionName: acceptedVersionName,
|
||||
});
|
||||
|
||||
if (isAll) {
|
||||
diff.buildAllUpgradePackages();
|
||||
}
|
||||
(() => {
|
||||
if (isAll) {
|
||||
diff.buildAllUpgradePackages();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (isClosest) {
|
||||
diff.buildClosestUpgradePackages();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isAll) {
|
||||
if (!versionFrom) {
|
||||
throw new Error("No 'version' specified.");
|
||||
}
|
||||
|
||||
diff.buildUpgradePackage(versionFrom);
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -1045,6 +1045,10 @@ input.global-search-input {
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
> input[type=checkbox] {
|
||||
margin: 3px 3px 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
.multi-enum-item-label-container {
|
||||
|
||||
+14
-6
@@ -27,14 +27,12 @@
|
||||
************************************************************************/
|
||||
|
||||
const fs = require('fs');
|
||||
const sys = require('util');
|
||||
const cp = require('child_process');
|
||||
const archiver = require('archiver');
|
||||
const process = require('process');
|
||||
const buildUtils = require('./build-utils');
|
||||
|
||||
const exec = cp.exec;
|
||||
const execSync = cp.execSync;
|
||||
|
||||
/**
|
||||
* Builds upgrade packages.
|
||||
@@ -59,13 +57,19 @@ class Diff
|
||||
return tagList;
|
||||
}
|
||||
|
||||
buildClosestUpgradePackages() {
|
||||
let versionFromList = this._getPreviousVersionList(true);
|
||||
|
||||
this.buildMultipleUpgradePackages(versionFromList);
|
||||
}
|
||||
|
||||
buildAllUpgradePackages() {
|
||||
let versionFromList = this._getPreviousVersionList();
|
||||
|
||||
this.buildMultipleUpgradePackages(versionFromList);
|
||||
}
|
||||
|
||||
_getPreviousVersionList() {
|
||||
_getPreviousVersionList(closest) {
|
||||
let dirInitial = process.cwd();
|
||||
|
||||
let version = (require(this.espoPath + '/package.json') || {}).version;
|
||||
@@ -105,6 +109,12 @@ class Diff
|
||||
for (let i = 0; i < tagList.length; i++) {
|
||||
let tag = tagList[i];
|
||||
|
||||
let patchVersionNumberI = tag.split('.')[2];
|
||||
|
||||
if (closest && parseInt(patchVersionNumberI) !== parseInt(hotfixVersionNumber) - 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (tag === version) {
|
||||
continue;
|
||||
}
|
||||
@@ -112,8 +122,6 @@ class Diff
|
||||
if (!~tag.indexOf('beta') && !~tag.indexOf('alpha')) {
|
||||
versionFromList.push(tag);
|
||||
|
||||
let patchVersionNumberI = tag.split('.')[2];
|
||||
|
||||
if (patchVersionNumberI === '0') {
|
||||
break;
|
||||
}
|
||||
@@ -156,7 +164,7 @@ class Diff
|
||||
return new Promise(resolve => {
|
||||
let acceptedVersionName = params.acceptedVersionName || versionFrom;
|
||||
let isDev = params.isDev;
|
||||
let withVendor = params.withVendor;
|
||||
let withVendor = params.withVendor ?? true;
|
||||
let forceScripts = params.forceScripts;
|
||||
|
||||
let version = (require(espoPath + '/package.json') || {}).version;
|
||||
|
||||
Generated
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "espocrm",
|
||||
"version": "7.2.1",
|
||||
"version": "7.2.3",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "espocrm",
|
||||
"version": "7.2.1",
|
||||
"version": "7.2.3",
|
||||
"description": "Open-source CRM.",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
Reference in New Issue
Block a user