snapshot of https://github.com/espocrm/espocrm.git (master, 2026-09-18; blobs > 131072B omitted)
Some checks failed
Test / Test on PHP 8.3 (push) Failing after 5s
Test / Test on PHP 8.4 (push) Failing after 4s
Test / Test on PHP 8.5 (push) Failing after 3s
TypeScript static analysis / TypeScript check (push) Failing after 14s
Test Integration on MySQL / Test on PHP 8.3 (push) Failing after 2s
Test Integration on MySQL / Test on PHP 8.5 (push) Failing after 0s
Test Integration on PostgreSQL / Test on PHP 8.4 fix (push) Failing after 1s
Test Integration on PostgreSQL / Test on PHP 8.4 master (push) Failing after 1s
Some checks failed
Test / Test on PHP 8.3 (push) Failing after 5s
Test / Test on PHP 8.4 (push) Failing after 4s
Test / Test on PHP 8.5 (push) Failing after 3s
TypeScript static analysis / TypeScript check (push) Failing after 14s
Test Integration on MySQL / Test on PHP 8.3 (push) Failing after 2s
Test Integration on MySQL / Test on PHP 8.5 (push) Failing after 0s
Test Integration on PostgreSQL / Test on PHP 8.4 fix (push) Failing after 1s
Test Integration on PostgreSQL / Test on PHP 8.4 master (push) Failing after 1s
This commit is contained in:
147
client/src/handlers/record/lock-action.js
Normal file
147
client/src/handlers/record/lock-action.js
Normal file
@@ -0,0 +1,147 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://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 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.
|
||||
************************************************************************/
|
||||
|
||||
import ActionHandler from 'action-handler';
|
||||
import {inject} from 'di';
|
||||
import AclManager from 'acl-manager';
|
||||
import Metadata from 'metadata';
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
export default class LockActionHandler extends ActionHandler {
|
||||
|
||||
/**
|
||||
* @type {AclManager}
|
||||
*/
|
||||
@inject(AclManager)
|
||||
acl
|
||||
|
||||
/**
|
||||
* @type {Metadata}
|
||||
*/
|
||||
@inject(Metadata)
|
||||
metadata
|
||||
|
||||
async actionLock() {
|
||||
const model = this.view.model;
|
||||
|
||||
Espo.Ui.notifyWait();
|
||||
|
||||
let attributes;
|
||||
|
||||
try {
|
||||
attributes = await Espo.Ajax.postRequest('Action', {
|
||||
action: 'lock',
|
||||
entityType: model.entityType,
|
||||
id: model.id,
|
||||
});
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
|
||||
model.setMultiple(attributes, {sync: true});
|
||||
model.trigger('sync', this.model, null, {});
|
||||
|
||||
Espo.Ui.success(this.view.translate('locked', 'messages'));
|
||||
}
|
||||
|
||||
async actionUnlock() {
|
||||
const model = this.view.model;
|
||||
|
||||
Espo.Ui.notifyWait();
|
||||
|
||||
let attributes;
|
||||
|
||||
try {
|
||||
attributes = await Espo.Ajax.postRequest('Action', {
|
||||
action: 'unlock',
|
||||
entityType: model.entityType,
|
||||
id: model.id,
|
||||
});
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
|
||||
model.setMultiple(attributes, {sync: true});
|
||||
model.trigger('sync', this.model, null, {});
|
||||
|
||||
Espo.Ui.success(this.view.translate('unlocked', 'messages'));
|
||||
}
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
/**
|
||||
* @return {boolean}
|
||||
*/
|
||||
canBeLocked() {
|
||||
const model = this.view.model;
|
||||
|
||||
if (!this.isEnabled(model.entityType)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.acl.getPermissionLevel('lock') !== 'yes') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (model.attributes.isLocked) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
/**
|
||||
* @return {boolean}
|
||||
*/
|
||||
canBeUnlocked() {
|
||||
const model = this.view.model;
|
||||
|
||||
if (!this.isEnabled(model.entityType)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.acl.getPermissionLevel('lock') !== 'yes') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!model.attributes.isLocked) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {string} entityType
|
||||
* @return {boolean}
|
||||
*/
|
||||
isEnabled(entityType) {
|
||||
return this.metadata.get(`scopes.${entityType}.lockable`) === true;
|
||||
}
|
||||
}
|
||||
145
client/src/handlers/record/lock-mass-action.js
Normal file
145
client/src/handlers/record/lock-mass-action.js
Normal file
@@ -0,0 +1,145 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://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 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.
|
||||
************************************************************************/
|
||||
|
||||
import ActionHandler from 'action-handler';
|
||||
import {inject} from 'di';
|
||||
import AclManager from 'acl-manager';
|
||||
import Language from 'language';
|
||||
import MassActionHelper from 'helpers/mass-action';
|
||||
import Metadata from 'metadata';
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
export default class LockMassActionHandler extends ActionHandler {
|
||||
|
||||
/**
|
||||
* @type {AclManager}
|
||||
*/
|
||||
@inject(AclManager)
|
||||
acl
|
||||
|
||||
/**
|
||||
* @type {Language}
|
||||
*/
|
||||
@inject(Language)
|
||||
language
|
||||
|
||||
/**
|
||||
* @type {Metadata}
|
||||
*/
|
||||
@inject(Metadata)
|
||||
metadata
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
async actionLock() {
|
||||
const msg = this.language.translate('confirmMassLock', 'messages');
|
||||
|
||||
await this.view.confirm(msg);
|
||||
|
||||
await this.process('lock');
|
||||
}
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
async actionUnlock() {
|
||||
const msg = this.language.translate('confirmMassUnlock', 'messages');
|
||||
|
||||
await this.view.confirm(msg);
|
||||
|
||||
await this.process('unlock');
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {string} action
|
||||
*/
|
||||
async process(action) {
|
||||
const helper = new MassActionHelper(this.view);
|
||||
const params = this.view.getMassActionSelectionPostData();
|
||||
const idle = !!params.searchParams && helper.checkIsIdle(this.view.collection.total);
|
||||
|
||||
const onDone = count => {
|
||||
const labelKey = action === 'lock' ? 'massLockDone': 'massUnlockDone';
|
||||
|
||||
const msg = this.view.translate(labelKey, 'messages')
|
||||
.replace('{count}', count.toString());
|
||||
|
||||
Espo.Ui.success(msg);
|
||||
};
|
||||
|
||||
Espo.Ui.notifyWait();
|
||||
|
||||
const result = await Espo.Ajax.postRequest('MassAction', {
|
||||
entityType: this.view.entityType,
|
||||
action: action,
|
||||
params: params,
|
||||
idle: idle,
|
||||
});
|
||||
|
||||
if (result.id) {
|
||||
const view = await helper.process(result.id, action)
|
||||
|
||||
this.view.listenToOnce(view, 'close:success', result => onDone(result.count));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
onDone(result.count);
|
||||
}
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
initLock() {
|
||||
if (
|
||||
!this.view.collection ||
|
||||
!this.isEnabled(this.view.collection.entityType) ||
|
||||
this.acl.getPermissionLevel('massUpdate') !== 'yes' ||
|
||||
this.acl.getPermissionLevel('lock') !== 'yes'
|
||||
) {
|
||||
this.view.removeMassAction('lock');
|
||||
}
|
||||
}
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
initUnlock() {
|
||||
if (
|
||||
!this.view.collection ||
|
||||
!this.isEnabled(this.view.collection.entityType) ||
|
||||
this.acl.getPermissionLevel('massUpdate') !== 'yes' ||
|
||||
this.acl.getPermissionLevel('lock') !== 'yes'
|
||||
) {
|
||||
this.view.removeMassAction('unlock');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {string} entityType
|
||||
* @return {boolean}
|
||||
*/
|
||||
isEnabled(entityType) {
|
||||
return this.metadata.get(`scopes.${entityType}.lockable`) === true;
|
||||
}
|
||||
}
|
||||
163
client/src/handlers/record/lock-view-setup.js
Normal file
163
client/src/handlers/record/lock-view-setup.js
Normal file
@@ -0,0 +1,163 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://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 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.
|
||||
************************************************************************/
|
||||
|
||||
import {inject} from 'di';
|
||||
import Metadata from 'metadata';
|
||||
import AssignmentHelper from 'helpers/assignment';
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
export default class LockViewSetup {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Metadata}
|
||||
*/
|
||||
@inject(Metadata)
|
||||
metadata
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import('model').default}
|
||||
*/
|
||||
model
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import('views/record/detail').default}
|
||||
*/
|
||||
view
|
||||
|
||||
ignoreFieldList = [
|
||||
'isLocked',
|
||||
'modifiedAt',
|
||||
'modifiedBy',
|
||||
'streamUpdatedAt',
|
||||
]
|
||||
|
||||
/**
|
||||
* @param {import('views/record/detail').default} view
|
||||
*/
|
||||
constructor(view) {
|
||||
this.view = view;
|
||||
this.model = view.model;
|
||||
}
|
||||
|
||||
process() {
|
||||
const entityType = this.model.entityType;
|
||||
|
||||
if (this.metadata.get(`scopes.${entityType}.lockable`) !== true) {
|
||||
return;
|
||||
}
|
||||
|
||||
let wasLocked = false;
|
||||
const lockedMap = {};
|
||||
|
||||
const ignoreFieldList = this.getIgnoreFieldList();
|
||||
|
||||
const fieldsDefs = /** @type {Record.<string, Record>} */
|
||||
this.metadata.get(`entityDefs.${entityType}.fields`) ?? {};
|
||||
|
||||
const lockableFields = Object.keys(fieldsDefs)
|
||||
.filter(field => {
|
||||
if (ignoreFieldList.includes(field)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const defs = fieldsDefs[field];
|
||||
|
||||
return !defs.notLockable &&
|
||||
!defs.readOnly &&
|
||||
!defs.readOnlyAfterCreate;
|
||||
});
|
||||
|
||||
const controlLocked = () => {
|
||||
const isLocked = this.model.attributes.isLocked;
|
||||
|
||||
if (!isLocked && !wasLocked) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isLocked) {
|
||||
wasLocked = true;
|
||||
}
|
||||
|
||||
lockableFields.forEach(field => {
|
||||
if (isLocked) {
|
||||
if (
|
||||
this.view.recordHelper &&
|
||||
this.view.recordHelper.getFieldStateParam(field, 'readOnly')
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
lockedMap[field] = true;
|
||||
|
||||
this.view.setFieldReadOnly(field);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!lockedMap[field]) {
|
||||
return;
|
||||
}
|
||||
|
||||
delete lockedMap[field];
|
||||
|
||||
this.view.setFieldNotReadOnly(field);
|
||||
});
|
||||
}
|
||||
|
||||
controlLocked();
|
||||
this.view.listenTo(this.model, 'change:isLocked', () => controlLocked());
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @return {string[]}
|
||||
*/
|
||||
getIgnoreFieldList() {
|
||||
const entityType = this.model.entityType;
|
||||
|
||||
const ignoreFieldList = [...this.ignoreFieldList];
|
||||
|
||||
const helper = new AssignmentHelper;
|
||||
|
||||
if (helper.hasCollaboratorsField(entityType)) {
|
||||
if (helper.hasAssignedUsersField(entityType)) {
|
||||
if (this.model.getFieldParam('assignedUsers', 'notLockable')) {
|
||||
ignoreFieldList.push('collaborators');
|
||||
}
|
||||
} else if (helper.hasAssignedUserField(entityType)) {
|
||||
if (this.model.getFieldParam('assignedUser', 'notLockable')) {
|
||||
ignoreFieldList.push('collaborators');
|
||||
}
|
||||
}
|
||||
}
|
||||
return ignoreFieldList;
|
||||
}
|
||||
}
|
||||
145
client/src/handlers/record/pipeline-view-setup.js
Normal file
145
client/src/handlers/record/pipeline-view-setup.js
Normal file
@@ -0,0 +1,145 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://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 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.
|
||||
************************************************************************/
|
||||
import {inject} from 'di';
|
||||
import Metadata from 'metadata';
|
||||
import AppParams from 'app-params';
|
||||
import PipelinesHelper from 'helpers/misc/pipelines';
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
export default class PipelineViewSetupHandler {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Metadata}
|
||||
*/
|
||||
@inject(Metadata)
|
||||
metadata
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import('model').default}
|
||||
*/
|
||||
model
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import('views/record/detail').default}
|
||||
*/
|
||||
view
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {AppParams}
|
||||
*/
|
||||
@inject(AppParams)
|
||||
appParams
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {{id: string, stages: {id: string, name: string, style: string|null}[]}[]}
|
||||
*/
|
||||
pipelines
|
||||
|
||||
/**
|
||||
* @param {import('views/record/detail').default} view
|
||||
*/
|
||||
constructor(view) {
|
||||
this.view = view;
|
||||
this.model = view.model;
|
||||
}
|
||||
|
||||
process() {
|
||||
const entityType = this.model.entityType;
|
||||
|
||||
if (this.metadata.get(`scopes.${entityType}.pipelines`) !== true) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.pipelines = new PipelinesHelper().get(entityType);
|
||||
|
||||
this.model.onChange({
|
||||
owner: this.view,
|
||||
attributes: ['pipelineId'],
|
||||
callback: o => {
|
||||
if (!o.ui) {
|
||||
return;
|
||||
}
|
||||
|
||||
setTimeout(() => this.updateStage(), 1);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
updateStage() {
|
||||
const pipelineId = this.model.attributes.pipelineId;
|
||||
|
||||
if (!pipelineId) {
|
||||
this.setStageNull();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const pipeline = this.pipelines.find(it => it.id === pipelineId);
|
||||
|
||||
if (!pipeline) {
|
||||
this.setStageNull();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const stage = pipeline.stages[0];
|
||||
|
||||
if (!stage) {
|
||||
this.setStageNull();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.model.setMultiple({
|
||||
pipelineStageId: stage.id,
|
||||
pipelineStageName: stage.name,
|
||||
});
|
||||
|
||||
this.model.trigger('pipeline-changed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
setStageNull() {
|
||||
this.model.setMultiple({
|
||||
pipelineStageId: null,
|
||||
pipelineStageName: null,
|
||||
});
|
||||
|
||||
this.model.trigger('pipeline-changed');
|
||||
}
|
||||
}
|
||||
72
client/src/handlers/record/view-audit-log.js
Normal file
72
client/src/handlers/record/view-audit-log.js
Normal file
@@ -0,0 +1,72 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://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 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.
|
||||
************************************************************************/
|
||||
|
||||
import StreamViewAuditLogModalView from 'views/stream/modals/view-audit-log';
|
||||
|
||||
class ViewAuditLogHandler {
|
||||
|
||||
constructor(/** import('views/record/detail').default */view) {
|
||||
this.view = view;
|
||||
this.metadata = /** @type {module:metadata} */view.getMetadata();
|
||||
this.entityType = this.view.entityType;
|
||||
this.model = /** @type {module:model} */this.view.model;
|
||||
|
||||
this.hasAudited =
|
||||
this.metadata.get(`scopes.${this.entityType}.statusField`) ||
|
||||
this.model.getFieldList().find(field => this.model.getFieldParam(field, 'audited')) !== undefined;
|
||||
|
||||
if (this.entityType === 'User' && !this.view.getUser().isAdmin()) {
|
||||
this.hasAudited = false;
|
||||
}
|
||||
|
||||
if (this.view.getUser().isPortal()) {
|
||||
this.hasAudited = false;
|
||||
}
|
||||
|
||||
if (this.view.getAcl().getPermissionLevel('audit') !== 'yes') {
|
||||
this.hasAudited = false;
|
||||
}
|
||||
}
|
||||
|
||||
isAvailable() {
|
||||
return this.hasAudited;
|
||||
}
|
||||
|
||||
show() {
|
||||
const view = new StreamViewAuditLogModalView({model: this.model});
|
||||
|
||||
this.view.assignView('dialog', view)
|
||||
.then(() => {
|
||||
view.render();
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
export default ViewAuditLogHandler;
|
||||
|
||||
120
client/src/handlers/record/view-user-access.js
Normal file
120
client/src/handlers/record/view-user-access.js
Normal file
@@ -0,0 +1,120 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://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 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.
|
||||
************************************************************************/
|
||||
|
||||
import RelatedListModalView from 'views/modals/related-list';
|
||||
|
||||
export default class {
|
||||
|
||||
toShow
|
||||
|
||||
constructor(/** import('views/record/detail').default */view) {
|
||||
this.view = view;
|
||||
this.metadata = /** @type {module:metadata} */view.getMetadata();
|
||||
this.entityType = this.view.entityType;
|
||||
this.model = this.view.model;
|
||||
|
||||
const level = this.view.getAcl().getPermissionLevel('user');
|
||||
|
||||
this.toShow = (level === 'all' || level === 'team') &&
|
||||
(
|
||||
this.metadata.get(`scopes.${this.entityType}.object`) ||
|
||||
this.metadata.get(`scopes.${this.entityType}.acl`)
|
||||
)
|
||||
this.view.getAcl().checkScope('User');
|
||||
}
|
||||
|
||||
isAvailable() {
|
||||
return this.toShow;
|
||||
}
|
||||
|
||||
async show() {
|
||||
const actionList = this.getActionList();
|
||||
|
||||
/** @type {Record[]} */
|
||||
const listLayout = [
|
||||
{
|
||||
name: 'name',
|
||||
link: true,
|
||||
view: 'views/user/fields/name',
|
||||
},
|
||||
];
|
||||
|
||||
//const width = Math.round((100.0 - 40) / (actionList.length + 1));
|
||||
|
||||
actionList.forEach(action => {
|
||||
listLayout.push({
|
||||
name: 'recordAccessLevel' + action,
|
||||
customLabel: this.view.translate(action, 'recordActions'),
|
||||
view: 'views/user/fields/record-access-level',
|
||||
notSortable: true,
|
||||
width: 16,
|
||||
});
|
||||
});
|
||||
|
||||
const view = new RelatedListModalView({
|
||||
model: this.model,
|
||||
link: 'usersAccess',
|
||||
entityType: 'User',
|
||||
title: this.view.translate('View User Access'),
|
||||
url: `${this.entityType}/${this.model.id}/usersAccess`,
|
||||
createDisabled: true,
|
||||
selectDisabled: true,
|
||||
massActionsDisabled: true,
|
||||
maxSize: this.view.getConfig().get('recordsPerPageSmall'),
|
||||
rowActionsView: null,
|
||||
listLayout: listLayout,
|
||||
filter: 'active',
|
||||
});
|
||||
|
||||
await this.view.assignView('dialog', view);
|
||||
await view.render();
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @return {string[]}
|
||||
*/
|
||||
getActionList() {
|
||||
/** @type {string[]} */
|
||||
let actionList = this.metadata.get(`scopes.${this.entityType}.aclActionList`);
|
||||
|
||||
if (!actionList) {
|
||||
actionList = [
|
||||
'read',
|
||||
'edit',
|
||||
'delete',
|
||||
];
|
||||
|
||||
if (this.metadata.get(`scopes.${this.entityType}.stream`)) {
|
||||
actionList.push('stream');
|
||||
}
|
||||
}
|
||||
|
||||
return actionList.filter(it => it !== 'create');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user